diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..797e01fc52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,30 @@ + + +**Is this a BUG REPORT or FEATURE REQUEST?**: + +> Uncomment only one, leave it on its own line: +> +> /kind bug +> /kind feature + + +**What happened**: + +**What you expected to happen**: + +**How to reproduce it (as minimally and precisely as possible)**: + + +**Anything else we need to know?**: + +**Environment**: +- Restcomm Connect version (from startup logs): +- Cloud provider or hardware configuration: +- OS (e.g. from /etc/os-release): +- Kernel (e.g. `uname -a`): +- Deployment method (e.g. `docker-compose`, with linked `docker-compose.yml` file, +or application server info + deployment option): +- Others: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..0b564dd459 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ + + +**What this PR does / why we need it**: + +**Which issue(s) this PR fixes** *(optional, in `fixes #(, fixes #, ...)` format, will close the issue(s) when PR gets merged)*: +Fixes # + +**Special notes for your reviewer**: diff --git a/.gitignore b/.gitignore index 2f6a7af067..b92a79e654 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,8 @@ bin/ *.class logs bin +.DS_Store +**/*~ +csv +.metadata +.idea diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 0000000000..7fb8ed00de --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..d6012441ae --- /dev/null +++ b/.travis.yml @@ -0,0 +1,36 @@ +language: java +jdk: + - oraclejdk8 +branches: + only: + - master + - /^deploy-.*$/ +email: + recipients: + - gvagenas@telestax.com + - jean.deruelle@telestax.com + on_success: never # default: change + on_failure: always # default: always +cache: + directories: + - $HOME/.m2 +addons: + sonarqube: + organization: "restcomm-connect" # the key of the org you chose at step #3 +script: + - ./build.sh +after_success: + - cd restcomm + - mvn com.blackducksoftware.integration:hub-maven-plugin:2.0.2:build-bom -Dhub.output.directory=. -Dhub.deploy.bdio=false + - bash <(curl -s https://copilot.blackducksoftware.com/bash/travis) ./*_bdio.jsonld +# Problem to run testsuite https://github.com/travis-ci/travis-ci/issues/1382 +# - echo "About to run sonar-scanner" +# - cd restcomm +# - pwd +# - sed -i 's/\/\/g' ./restcomm.testsuite/src/test/resources/log4j.xml +# - sed -i 's/DEBUG/OFF/g' ./restcomm.testsuite/src/test/resources/akka_application.conf +# - sed -i 's/INFO/OFF/g' ./restcomm.application/src/main/resources/application.conf +# - mvn -q clean org.jacoco:jacoco-maven-plugin:prepare-agent surefire-report:report sonar:sonar > ./surefire-report-output.txt +# - curl -T restcomm.testsuite/target/site/surefire-report.html -ugvagenas:$BINTRAY_API_KEY -H "X-Bintray-Package:binaries" -H "X-Bintray-Version:8.2.0" https://api.bintray.com/content/gvagenas/Restcomm-Connect/bin/surefire-report-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER.html +# - curl -T ./surefire-report-output.txt -ugvagenas:$BINTRAY_API_KEY -H "X-Bintray-Package:binaries" -H "X-Bintray-Version:8.2.0" https://api.bintray.com/content/gvagenas/Restcomm-Connect/bin/surefire-report-output-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER.txt diff --git a/CHANGELOG_8.2.1.md b/CHANGELOG_8.2.1.md new file mode 100644 index 0000000000..de5a0a441c --- /dev/null +++ b/CHANGELOG_8.2.1.md @@ -0,0 +1,1223 @@ +# Change Log + +## [Unreleased](https://github.com/RestComm/Restcomm-Connect/tree/HEAD) + +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-67...HEAD) + +**Closed issues:** + +- 'SmsStatus' is not added as parameter for statusCallBack [\#2577](https://github.com/RestComm/Restcomm-Connect/issues/2577) + +## [8.2.1-67](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-67) (2017-10-13) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-66...8.2.1-67) + +## [8.2.1-66](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-66) (2017-10-13) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-65...8.2.1-66) + +**Closed issues:** + +- Fix url to RVD in Dashboard [\#2576](https://github.com/RestComm/Restcomm-Connect/issues/2576) + +## [8.2.1-65](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-65) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-64...8.2.1-65) + +## [8.2.1-64](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-64) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-63...8.2.1-64) + +## [8.2.1-63](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-63) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-62...8.2.1-63) + +## [8.2.1-62](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-62) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-61...8.2.1-62) + +## [8.2.1-61](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-61) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-60...8.2.1-61) + +## [8.2.1-60](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-60) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1322...8.2.1-60) + +## [8.2.0.1322](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1322) (2017-10-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-59...8.2.0.1322) + +## [8.2.1-59](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-59) (2017-10-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-56...8.2.1-59) + +**Merged pull requests:** + +- Issue2568 [\#2575](https://github.com/RestComm/Restcomm-Connect/pull/2575) ([jaimecasero](https://github.com/jaimecasero)) + +## [8.2.1-56](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-56) (2017-10-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-55...8.2.1-56) + +## [8.2.1-55](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-55) (2017-10-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-53...8.2.1-55) + +**Closed issues:** + +- Create the flow for applications and templates [\#2570](https://github.com/RestComm/Restcomm-Connect/issues/2570) + +## [8.2.1-53](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-53) (2017-10-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-52...8.2.1-53) + +**Closed issues:** + +- Optimize application retrival API wrt Numbers [\#2517](https://github.com/RestComm/Restcomm-Connect/issues/2517) +- Modify MockMediaGateway to properly create recording file [\#2480](https://github.com/RestComm/Restcomm-Connect/issues/2480) +- Restcomm exception prevents 200 OK response to MESSAGE to be sent to message sender [\#1023](https://github.com/RestComm/Restcomm-Connect/issues/1023) + +**Merged pull requests:** + +- Issue2480 Record refactoring [\#2569](https://github.com/RestComm/Restcomm-Connect/pull/2569) ([gvagenas](https://github.com/gvagenas)) +- Restcomm1147 rms resources leak on conf [\#2564](https://github.com/RestComm/Restcomm-Connect/pull/2564) ([gvagenas](https://github.com/gvagenas)) +- Issue2517 application api with numbers [\#2550](https://github.com/RestComm/Restcomm-Connect/pull/2550) ([otsakir](https://github.com/otsakir)) + +## [8.2.1-52](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-52) (2017-10-10) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-51...8.2.1-52) + +**Merged pull requests:** + +- Issue 2521: Move DownloaderResponse access after succeeded\(\) check [\#2549](https://github.com/RestComm/Restcomm-Connect/pull/2549) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.1-51](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-51) (2017-10-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-50...8.2.1-51) + +**Closed issues:** + +- RestComm-Connect USSD PUSH API \>\>\> HTTP Status 500 - Internal Server Error [\#2551](https://github.com/RestComm/Restcomm-Connect/issues/2551) +- Implement/Enhance Restcomm Console Analytics page for Mobile [\#2538](https://github.com/RestComm/Restcomm-Connect/issues/2538) +- Implement/Enhance Restcomm Console Analytics page for Desktop [\#2537](https://github.com/RestComm/Restcomm-Connect/issues/2537) +- Implement/Enhance Restcomm Console Accounts page for Mobile [\#2536](https://github.com/RestComm/Restcomm-Connect/issues/2536) +- Implement/Enhance Restcomm Console Accounts page for Desktop [\#2535](https://github.com/RestComm/Restcomm-Connect/issues/2535) + +**Merged pull requests:** + +- Push notification server support for text messages [\#2548](https://github.com/RestComm/Restcomm-Connect/pull/2548) ([agafox](https://github.com/agafox)) +- Fixed 'IsPushEnabled' handling in update RC client API call [\#2542](https://github.com/RestComm/Restcomm-Connect/pull/2542) ([agafox](https://github.com/agafox)) + +## [8.2.1-50](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-50) (2017-10-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-49...8.2.1-50) + +**Closed issues:** + +- Create design document for Application api optimization [\#2523](https://github.com/RestComm/Restcomm-Connect/issues/2523) + +## [8.2.1-49](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-49) (2017-10-08) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-48...8.2.1-49) + +## [8.2.1-48](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-48) (2017-10-07) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-47...8.2.1-48) + +## [8.2.1-47](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-47) (2017-10-06) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-46...8.2.1-47) + +## [8.2.1-46](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-46) (2017-10-06) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-45...8.2.1-46) + +**Closed issues:** + +- Spike - Provide feedback during the Implementation of User's dropdown, Accounts, Sub accounts, analytics [\#2533](https://github.com/RestComm/Restcomm-Connect/issues/2533) +- Update Account api for organization [\#2525](https://github.com/RestComm/Restcomm-Connect/issues/2525) + +## [8.2.1-45](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-45) (2017-10-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-44...8.2.1-45) + +## [8.2.1-44](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-44) (2017-10-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1320...8.2.1-44) + +## [8.2.0.1320](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1320) (2017-10-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-43...8.2.0.1320) + +**Merged pull requests:** + +- Tweaked configuration scripts to work with RVD\_UNDEPLOY env variable [\#2506](https://github.com/RestComm/Restcomm-Connect/pull/2506) ([otsakir](https://github.com/otsakir)) + +## [8.2.1-43](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-43) (2017-10-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1319...8.2.1-43) + +**Merged pull requests:** + +- Issue2271 customer work [\#2543](https://github.com/RestComm/Restcomm-Connect/pull/2543) ([jaimecasero](https://github.com/jaimecasero)) +- Issue 2525 [\#2534](https://github.com/RestComm/Restcomm-Connect/pull/2534) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1319](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1319) (2017-10-03) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1318...8.2.0.1319) + +## [8.2.0.1318](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1318) (2017-10-03) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-42...8.2.0.1318) + +## [8.2.1-42](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-42) (2017-10-02) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-41...8.2.1-42) + +## [8.2.1-41](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-41) (2017-10-01) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1317...8.2.1-41) + +## [8.2.0.1317](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1317) (2017-09-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-40...8.2.0.1317) + +## [8.2.1-40](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-40) (2017-09-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1316...8.2.1-40) + +## [8.2.0.1316](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1316) (2017-09-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-39...8.2.0.1316) + +## [8.2.1-39](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-39) (2017-09-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1315...8.2.1-39) + +## [8.2.0.1315](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1315) (2017-09-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1314...8.2.0.1315) + +**Merged pull requests:** + +- Enh pooling [\#2528](https://github.com/RestComm/Restcomm-Connect/pull/2528) ([jaimecasero](https://github.com/jaimecasero)) +- Enh parallel4 - testsuite refactored to allow parallel exec [\#2527](https://github.com/RestComm/Restcomm-Connect/pull/2527) ([jaimecasero](https://github.com/jaimecasero)) + +## [8.2.0.1314](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1314) (2017-09-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-38...8.2.0.1314) + +## [8.2.1-38](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-38) (2017-09-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1313...8.2.1-38) + +## [8.2.0.1313](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1313) (2017-09-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1312...8.2.0.1313) + +**Closed issues:** + +- Implement/Enhance Restcomm Console Home page for Mobile [\#2489](https://github.com/RestComm/Restcomm-Connect/issues/2489) +- Implement/Enhance Restcomm Console Home page for Desktop [\#2488](https://github.com/RestComm/Restcomm-Connect/issues/2488) +- Implement/Enhance Restcomm Console Sign-In page for Mobile [\#2487](https://github.com/RestComm/Restcomm-Connect/issues/2487) +- Implement/Enhance Restcomm Console Sign-In page for Desktop [\#2486](https://github.com/RestComm/Restcomm-Connect/issues/2486) + +**Merged pull requests:** + +- Issue 2493 [\#2522](https://github.com/RestComm/Restcomm-Connect/pull/2522) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1312](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1312) (2017-09-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-37...8.2.0.1312) + +## [8.2.1-37](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-37) (2017-09-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-36...8.2.1-37) + +**Closed issues:** + +- Discuss application retrieval API optimization [\#2520](https://github.com/RestComm/Restcomm-Connect/issues/2520) +- Check issues at TADHack environment reported by some participants [\#2498](https://github.com/RestComm/Restcomm-Connect/issues/2498) + +## [8.2.1-36](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-36) (2017-09-26) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1311...8.2.1-36) + +## [8.2.0.1311](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1311) (2017-09-25) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-35...8.2.0.1311) + +**Closed issues:** + +- Rework the Ui of the Console and create mock-ups for Visual Designer templates [\#2499](https://github.com/RestComm/Restcomm-Connect/issues/2499) + +## [8.2.1-35](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-35) (2017-09-25) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-34...8.2.1-35) + +## [8.2.1-34](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-34) (2017-09-24) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-33...8.2.1-34) + +## [8.2.1-33](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-33) (2017-09-23) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-32...8.2.1-33) + +## [8.2.1-32](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-32) (2017-09-22) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1310...8.2.1-32) + +## [8.2.0.1310](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1310) (2017-09-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-31...8.2.0.1310) + +**Closed issues:** + +- Create connection pooling to RVD [\#2502](https://github.com/RestComm/Restcomm-Connect/issues/2502) + +**Merged pull requests:** + +- use instance ip as fallback domain name [\#2513](https://github.com/RestComm/Restcomm-Connect/pull/2513) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.1-31](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-31) (2017-09-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1309...8.2.1-31) + +## [8.2.0.1309](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1309) (2017-09-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-30...8.2.0.1309) + +**Closed issues:** + +- html-css mock-ups for the parts of the main page of the dashboard [\#2484](https://github.com/RestComm/Restcomm-Connect/issues/2484) + +**Merged pull requests:** + +- IVR test fix [\#2511](https://github.com/RestComm/Restcomm-Connect/pull/2511) ([YevgenL](https://github.com/YevgenL)) +- Asr [\#2500](https://github.com/RestComm/Restcomm-Connect/pull/2500) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.1-30](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-30) (2017-09-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1308...8.2.1-30) + +**Merged pull requests:** + +- Recording issue fix [\#2507](https://github.com/RestComm/Restcomm-Connect/pull/2507) ([YevgenL](https://github.com/YevgenL)) + +## [8.2.0.1308](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1308) (2017-09-19) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-29...8.2.0.1308) + +**Closed issues:** + +- UserAgentManager IndexOutOfBoundsException [\#2504](https://github.com/RestComm/Restcomm-Connect/issues/2504) + +## [8.2.1-29](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-29) (2017-09-19) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.1-27...8.2.1-29) + +## [8.2.1-27](https://github.com/RestComm/Restcomm-Connect/tree/8.2.1-27) (2017-09-18) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1307...8.2.1-27) + +**Closed issues:** + +- Spike - Make the Console responsive [\#2479](https://github.com/RestComm/Restcomm-Connect/issues/2479) + +## [8.2.0.1307](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1307) (2017-09-15) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1306...8.2.0.1307) + +**Closed issues:** + +- Downloader fails and as a result call is not cleaned up [\#2501](https://github.com/RestComm/Restcomm-Connect/issues/2501) + +## [8.2.0.1306](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1306) (2017-09-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1305...8.2.0.1306) + +**Closed issues:** + +- Spike - Finalise the content of the main page [\#2475](https://github.com/RestComm/Restcomm-Connect/issues/2475) + +## [8.2.0.1305](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1305) (2017-09-13) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1304...8.2.0.1305) + +## [8.2.0.1304](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1304) (2017-09-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1303...8.2.0.1304) + +**Closed issues:** + +- html - css mock-ups for the sign in page of the console [\#2483](https://github.com/RestComm/Restcomm-Connect/issues/2483) + +**Merged pull requests:** + +- Hints limitation [\#2471](https://github.com/RestComm/Restcomm-Connect/pull/2471) ([YevgenL](https://github.com/YevgenL)) + +## [8.2.0.1303](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1303) (2017-09-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1302...8.2.0.1303) + +**Closed issues:** + +- Wrong port in 'docker run' command in docs quick start [\#2494](https://github.com/RestComm/Restcomm-Connect/issues/2494) + +## [8.2.0.1302](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1302) (2017-09-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1301...8.2.0.1302) + +**Closed issues:** + +- Create a convention that will build RVD origin from current/available organization in Dashboard [\#2255](https://github.com/RestComm/Restcomm-Connect/issues/2255) +- Adapt CORS filter to multiple domains \(organizations\) [\#2254](https://github.com/RestComm/Restcomm-Connect/issues/2254) + +## [8.2.0.1301](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1301) (2017-09-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1300...8.2.0.1301) + +**Closed issues:** + +- support dial sip to number/client of a differnt organization [\#2109](https://github.com/RestComm/Restcomm-Connect/issues/2109) +- Make SIP Number and SIP Client tied to an account and Unique per Organization [\#2106](https://github.com/RestComm/Restcomm-Connect/issues/2106) +- Create a separate Domain Table tied 1:N to an account [\#2073](https://github.com/RestComm/Restcomm-Connect/issues/2073) + +## [8.2.0.1300](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1300) (2017-09-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1299...8.2.0.1300) + +## [8.2.0.1299](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1299) (2017-09-10) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1298...8.2.0.1299) + +**Closed issues:** + +- Add DateTime at MonitoringService response [\#2491](https://github.com/RestComm/Restcomm-Connect/issues/2491) +- Create html-css mock-ups of the main page of the Console [\#2442](https://github.com/RestComm/Restcomm-Connect/issues/2442) +- Create unit tests for dial-forking patches at VoiceInterpreter [\#2436](https://github.com/RestComm/Restcomm-Connect/issues/2436) + +## [8.2.0.1298](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1298) (2017-09-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1297...8.2.0.1298) + +**Closed issues:** + +- Account creation for Restcomm cloud with Salesforce.com approval automation [\#2478](https://github.com/RestComm/Restcomm-Connect/issues/2478) + +**Merged pull requests:** + +- Fix broken link to contributors guide on README.md [\#2465](https://github.com/RestComm/Restcomm-Connect/pull/2465) ([gsaslis](https://github.com/gsaslis)) + +## [8.2.0.1297](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1297) (2017-09-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1296...8.2.0.1297) + +**Closed issues:** + +- Pass the new Main page of the console to inVision and create the flow [\#2441](https://github.com/RestComm/Restcomm-Connect/issues/2441) + +**Merged pull requests:** + +- Push Notification Server configuration [\#2476](https://github.com/RestComm/Restcomm-Connect/pull/2476) ([agafox](https://github.com/agafox)) + +## [8.2.0.1296](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1296) (2017-09-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1295...8.2.0.1296) + +**Closed issues:** + +- SIP BYE not answered when sent from USSD Gw after dialogtimeout occurs [\#2411](https://github.com/RestComm/Restcomm-Connect/issues/2411) + +**Merged pull requests:** + +- HttpClient lazy initialization [\#2472](https://github.com/RestComm/Restcomm-Connect/pull/2472) ([agafox](https://github.com/agafox)) + +## [8.2.0.1295](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1295) (2017-08-31) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1294...8.2.0.1295) + +**Closed issues:** + +- Update iOS quick start guide asciidoc to be in sync with latest release [\#2467](https://github.com/RestComm/Restcomm-Connect/issues/2467) +- Helping with the UI of Restcomm WebRTC Demo [\#2466](https://github.com/RestComm/Restcomm-Connect/issues/2466) +- Create the first mock-ups for the mobile version of the Console [\#2459](https://github.com/RestComm/Restcomm-Connect/issues/2459) +- Spike - Create the main page of the console with the content [\#2440](https://github.com/RestComm/Restcomm-Connect/issues/2440) + +**Merged pull requests:** + +- Fixed \#2467: Update iOS quick start guide asciidoc to be in sync with… [\#2468](https://github.com/RestComm/Restcomm-Connect/pull/2468) ([atsakiridis](https://github.com/atsakiridis)) + +## [8.2.0.1294](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1294) (2017-08-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1293...8.2.0.1294) + +**Closed issues:** + +- SIP message is not sent back to USSD Gw when externalServiceTimeout set in rvd.xml is reached [\#2410](https://github.com/RestComm/Restcomm-Connect/issues/2410) + +## [8.2.0.1293](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1293) (2017-08-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1292...8.2.0.1293) + +**Closed issues:** + +- Improve comment in restcomm.xml - response-timeout setting [\#2464](https://github.com/RestComm/Restcomm-Connect/issues/2464) + +## [8.2.0.1292](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1292) (2017-08-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1291...8.2.0.1292) + +**Merged pull requests:** + +- Issue 2073 - Organization phase 1 [\#2431](https://github.com/RestComm/Restcomm-Connect/pull/2431) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1291](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1291) (2017-08-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1290...8.2.0.1291) + +**Merged pull requests:** + +- Issue 2190 [\#2462](https://github.com/RestComm/Restcomm-Connect/pull/2462) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1290](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1290) (2017-08-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1289...8.2.0.1290) + +**Closed issues:** + +- Spike - Research for Console's mobile version [\#2458](https://github.com/RestComm/Restcomm-Connect/issues/2458) + +## [8.2.0.1289](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1289) (2017-08-23) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1288...8.2.0.1289) + +**Closed issues:** + +- Video-RCML-Sprint3-Customer-Work [\#2448](https://github.com/RestComm/Restcomm-Connect/issues/2448) +- Review list of PRs pending to merge [\#2447](https://github.com/RestComm/Restcomm-Connect/issues/2447) +- Ambiguous/misleading CDR status field writing: "COMPLETED" and "completed" [\#2162](https://github.com/RestComm/Restcomm-Connect/issues/2162) +- Reject notification is not sent to caller [\#1726](https://github.com/RestComm/Restcomm-Connect/issues/1726) + +**Merged pull requests:** + +- Change CDR status in uppercase to lowercase for 'completed' [\#2422](https://github.com/RestComm/Restcomm-Connect/pull/2422) ([FerUy](https://github.com/FerUy)) + +## [8.2.0.1288](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1288) (2017-08-22) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1287...8.2.0.1288) + +**Closed issues:** + +- Spike - Create a roadmap for the UI/UX changes [\#2439](https://github.com/RestComm/Restcomm-Connect/issues/2439) + +## [8.2.0.1287](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1287) (2017-08-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1286...8.2.0.1287) + +**Merged pull requests:** + +- Issue \#2411: Workaround: Send Bye when received DownloaderResponse in wrong state [\#2438](https://github.com/RestComm/Restcomm-Connect/pull/2438) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.0.1286](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1286) (2017-08-19) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1285...8.2.0.1286) + +**Merged pull requests:** + +- Issue2384 remove dialogic libs [\#2437](https://github.com/RestComm/Restcomm-Connect/pull/2437) ([ghjansen](https://github.com/ghjansen)) + +## [8.2.0.1285](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1285) (2017-08-19) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1284...8.2.0.1285) + +**Closed issues:** + +- DialAction is not executed when everyone is busy [\#2435](https://github.com/RestComm/Restcomm-Connect/issues/2435) +- StatusCallback is not sent when dial branch rejects the call [\#2434](https://github.com/RestComm/Restcomm-Connect/issues/2434) +- VoiceInterpreter fails after Dial fork reaches timeout limit [\#2433](https://github.com/RestComm/Restcomm-Connect/issues/2433) +- VoiceInterpreter fails after Dial fork receives BUSY from all call branches [\#2432](https://github.com/RestComm/Restcomm-Connect/issues/2432) +- Remove Dialogic libraries from public repository and modify bootstrap to download them from external server [\#2384](https://github.com/RestComm/Restcomm-Connect/issues/2384) + +**Merged pull requests:** + +- fix issue that creates loop in USSD PUSH [\#2419](https://github.com/RestComm/Restcomm-Connect/pull/2419) ([croufay](https://github.com/croufay)) + +## [8.2.0.1284](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1284) (2017-08-18) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1283...8.2.0.1284) + +**Merged pull requests:** + +- Added 'pr' parameter to ASR [\#2428](https://github.com/RestComm/Restcomm-Connect/pull/2428) ([YevgenL](https://github.com/YevgenL)) +- Fix for DTMF from MediaServer [\#2418](https://github.com/RestComm/Restcomm-Connect/pull/2418) ([YevgenL](https://github.com/YevgenL)) +- RC Client object updated with pushClientIdentity in terms of RPNS activity [\#2412](https://github.com/RestComm/Restcomm-Connect/pull/2412) ([agafox](https://github.com/agafox)) +- RESTCOMM-1014 : Parse outboundProxy Uri with port and params [\#2311](https://github.com/RestComm/Restcomm-Connect/pull/2311) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.0.1283](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1283) (2017-08-16) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.2415.14...8.2.0.1283) + +**Merged pull requests:** + +- RESTCOMM-885: Add Multiprovider Extension REST API doc [\#2426](https://github.com/RestComm/Restcomm-Connect/pull/2426) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.0.2415.14](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.2415.14) (2017-08-15) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1282...8.2.0.2415.14) + +## [8.2.0.1282](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1282) (2017-08-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.Issue1372.13...8.2.0.1282) + +**Closed issues:** + +- "completed" status callback comes up twice [\#2421](https://github.com/RestComm/Restcomm-Connect/issues/2421) + +## [8.2.0.Issue1372.13](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.Issue1372.13) (2017-08-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1281...8.2.0.Issue1372.13) + +**Closed issues:** + +- Video-RCML-Sprint2-Customer-Work-2 [\#2271](https://github.com/RestComm/Restcomm-Connect/issues/2271) + +**Merged pull requests:** + +- zendesk 34592 DTMF issue when using SIP INFO [\#2414](https://github.com/RestComm/Restcomm-Connect/pull/2414) ([xhoaluu](https://github.com/xhoaluu)) + +## [8.2.0.1281](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1281) (2017-08-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.issue-2073.12...8.2.0.1281) + +## [8.2.0.issue-2073.12](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.issue-2073.12) (2017-08-10) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1280...8.2.0.issue-2073.12) + +## [8.2.0.1280](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1280) (2017-08-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1279...8.2.0.1280) + +## [8.2.0.1279](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1279) (2017-08-07) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1278...8.2.0.1279) + +**Closed issues:** + +- Spike: Create a roadmap for Consoles Implementation [\#2379](https://github.com/RestComm/Restcomm-Connect/issues/2379) +- Create mock-up's for Visual Designer's new UX [\#2378](https://github.com/RestComm/Restcomm-Connect/issues/2378) +- RVD Send SMS does not support Unicode characters [\#2368](https://github.com/RestComm/Restcomm-Connect/issues/2368) + +**Merged pull requests:** + +- Added unit tests [\#2409](https://github.com/RestComm/Restcomm-Connect/pull/2409) ([YevgenL](https://github.com/YevgenL)) +- Fix: Go to the next Verb after silent [\#2408](https://github.com/RestComm/Restcomm-Connect/pull/2408) ([YevgenL](https://github.com/YevgenL)) +- FinalSpeech support without PartialResult [\#2407](https://github.com/RestComm/Restcomm-Connect/pull/2407) ([YevgenL](https://github.com/YevgenL)) +- Remove PartialCallback check. Add FinalResult tests [\#2405](https://github.com/RestComm/Restcomm-Connect/pull/2405) ([YevgenL](https://github.com/YevgenL)) + +## [8.2.0.1278](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1278) (2017-07-31) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1277...8.2.0.1278) + +**Closed issues:** + +- Update the Nexmo integration to pass the right domain when buying a number. [\#2270](https://github.com/RestComm/Restcomm-Connect/issues/2270) + +**Merged pull requests:** + +- Update gather-rcml documentation [\#2392](https://github.com/RestComm/Restcomm-Connect/pull/2392) ([YevgenL](https://github.com/YevgenL)) +- Deploy/undeploy bundled RVD through configuration [\#2351](https://github.com/RestComm/Restcomm-Connect/pull/2351) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1277](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1277) (2017-07-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1276...8.2.0.1277) + +**Closed issues:** + +- Errors in 'config-olympus.sh' script [\#2381](https://github.com/RestComm/Restcomm-Connect/issues/2381) +- Spike: Research and Brainstorm for Visual Designers UX [\#2377](https://github.com/RestComm/Restcomm-Connect/issues/2377) + +## [8.2.0.1276](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1276) (2017-07-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1275...8.2.0.1276) + +**Closed issues:** + +- Restcomm `acting-as-proxy` feature, provide option to disable SDP patching [\#2391](https://github.com/RestComm/Restcomm-Connect/issues/2391) +- Append instanceid with call-sid [\#1907](https://github.com/RestComm/Restcomm-Connect/issues/1907) +- Support Live Call Modification in a cluster [\#1312](https://github.com/RestComm/Restcomm-Connect/issues/1312) + +**Merged pull requests:** + +- Issue 2389 - API should return 404 if resource is not found instead of 500 [\#2399](https://github.com/RestComm/Restcomm-Connect/pull/2399) ([maria-farooq](https://github.com/maria-farooq)) +- Issue 2265 [\#2393](https://github.com/RestComm/Restcomm-Connect/pull/2393) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1275](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1275) (2017-07-25) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1274...8.2.0.1275) + +**Closed issues:** + +- Sms statusCallback attribute is misspelled [\#2386](https://github.com/RestComm/Restcomm-Connect/issues/2386) +- Corrections on the UI of the Console [\#2376](https://github.com/RestComm/Restcomm-Connect/issues/2376) +- Support regex in Organizations [\#2293](https://github.com/RestComm/Restcomm-Connect/issues/2293) + +**Merged pull requests:** + +- Small fix of unsafe code [\#2390](https://github.com/RestComm/Restcomm-Connect/pull/2390) ([YevgenL](https://github.com/YevgenL)) +- DTMF fix [\#2387](https://github.com/RestComm/Restcomm-Connect/pull/2387) ([YevgenL](https://github.com/YevgenL)) +- Issue 2038 remove yellow color [\#2239](https://github.com/RestComm/Restcomm-Connect/pull/2239) ([nguyenhien1807](https://github.com/nguyenhien1807)) + +## [8.2.0.1274](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1274) (2017-07-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1273...8.2.0.1274) + +**Merged pull requests:** + +- \#2206: Docker documentation fixes + Docker for Mac comments [\#2382](https://github.com/RestComm/Restcomm-Connect/pull/2382) ([agafox](https://github.com/agafox)) + +## [8.2.0.1273](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1273) (2017-07-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1272...8.2.0.1273) + +**Closed issues:** + +- Create and present the RVD roadmap and demo new UX for brownbag lunch even [\#2380](https://github.com/RestComm/Restcomm-Connect/issues/2380) + +## [8.2.0.1272](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1272) (2017-07-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1271...8.2.0.1272) + +**Closed issues:** + +- SmsSessionRequest Does not add X-RestComm-AccountSid [\#2374](https://github.com/RestComm/Restcomm-Connect/issues/2374) +- Make changes to the flow of the Console [\#2373](https://github.com/RestComm/Restcomm-Connect/issues/2373) + +## [8.2.0.1271](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1271) (2017-07-18) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1270...8.2.0.1271) + +**Closed issues:** + +- Flow and Mock-up for Managing Applications in Restcomm Console [\#2359](https://github.com/RestComm/Restcomm-Connect/issues/2359) +- On Dial invalid/unregistered client, VoiceInterpreter should either execute Dial Action or move the the next verb [\#2358](https://github.com/RestComm/Restcomm-Connect/issues/2358) +- Make changes to the mock-ups after Weekly meeting's brainstorm [\#2327](https://github.com/RestComm/Restcomm-Connect/issues/2327) +- Review and small additions to the flow of all InVision mock-ups [\#2300](https://github.com/RestComm/Restcomm-Connect/issues/2300) +- Finalise where Restcomm WebRTC Demo will appears [\#2299](https://github.com/RestComm/Restcomm-Connect/issues/2299) +- Pass the "Apps" mock-ups in InVision [\#2298](https://github.com/RestComm/Restcomm-Connect/issues/2298) +- Pass the Logs mock-ups in InVision [\#2297](https://github.com/RestComm/Restcomm-Connect/issues/2297) +- Issue with encoding of Unicode characters [\#1903](https://github.com/RestComm/Restcomm-Connect/issues/1903) + +## [8.2.0.1270](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1270) (2017-07-17) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1269...8.2.0.1270) + +**Closed issues:** + +- Implement dynamic RVD resolving based on configuration [\#2340](https://github.com/RestComm/Restcomm-Connect/issues/2340) +- A rough mock-up for Restcomm WebRTC Demo web supported features [\#2307](https://github.com/RestComm/Restcomm-Connect/issues/2307) +- Create configuration script that automatically updates dashboard.json/rvdUrl [\#2287](https://github.com/RestComm/Restcomm-Connect/issues/2287) +- Customer support epic for 'George's Sprint 5' [\#2280](https://github.com/RestComm/Restcomm-Connect/issues/2280) +- Unplanned work for 'George's Sprint 5' [\#2279](https://github.com/RestComm/Restcomm-Connect/issues/2279) +- App retrieval from AppStore fails in dashboard [\#2278](https://github.com/RestComm/Restcomm-Connect/issues/2278) +- Implement dynamic logic for CORS request filtering [\#2230](https://github.com/RestComm/Restcomm-Connect/issues/2230) +- Update rcmlserver-api/base-url in restcomm.xml through configuration [\#2212](https://github.com/RestComm/Restcomm-Connect/issues/2212) +- Configure video options rvd.xml from advanced.conf [\#2133](https://github.com/RestComm/Restcomm-Connect/issues/2133) + +**Merged pull requests:** + +- Issue2340 rvd resolving from config [\#2349](https://github.com/RestComm/Restcomm-Connect/pull/2349) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1269](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1269) (2017-07-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1268...8.2.0.1269) + +**Closed issues:** + +- Properly setup S3Client to be able to work with S3Ninja [\#2346](https://github.com/RestComm/Restcomm-Connect/issues/2346) + +**Merged pull requests:** + +- Add license scan status and report [\#2345](https://github.com/RestComm/Restcomm-Connect/pull/2345) ([xizhao](https://github.com/xizhao)) +- Issue2287 dashboard json upgrade script [\#2338](https://github.com/RestComm/Restcomm-Connect/pull/2338) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1268](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1268) (2017-07-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1267...8.2.0.1268) + +**Closed issues:** + +- NPE in B2BUAHelper for missing contact header in 180/ringing msgs [\#2341](https://github.com/RestComm/Restcomm-Connect/issues/2341) +- Provide custom executor for S3 Uploads [\#2339](https://github.com/RestComm/Restcomm-Connect/issues/2339) +- Call Api should send back proper response for request of updating completed calls [\#2330](https://github.com/RestComm/Restcomm-Connect/issues/2330) +- S3AccessTool shouldn't block waiting for the file [\#2324](https://github.com/RestComm/Restcomm-Connect/issues/2324) + +## [8.2.0.1267](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1267) (2017-07-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1266...8.2.0.1267) + +**Closed issues:** + +- Add gov.nist.javax.sip.TLS\_CLIENT\_AUTH\_TYPE configuratio. [\#2336](https://github.com/RestComm/Restcomm-Connect/issues/2336) +- Create design document for dynamic resolving of RVD location based on configuration [\#2296](https://github.com/RestComm/Restcomm-Connect/issues/2296) + +**Merged pull requests:** + +- TLS\_CLIENT\_AUTH\_TYPE configuration option. [\#2337](https://github.com/RestComm/Restcomm-Connect/pull/2337) ([leftyb](https://github.com/leftyb)) + +## [8.2.0.1266](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1266) (2017-07-08) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1265...8.2.0.1266) + +**Closed issues:** + +- DialStatusCallback might execute the same state more than once [\#2335](https://github.com/RestComm/Restcomm-Connect/issues/2335) +- Recording and Dial with record, race condition [\#2332](https://github.com/RestComm/Restcomm-Connect/issues/2332) + +## [8.2.0.1265](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1265) (2017-07-07) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.11...8.2.0.1265) + +**Closed issues:** + +- Child actors should be created using getContext\(\).actorOf\(\) [\#2274](https://github.com/RestComm/Restcomm-Connect/issues/2274) + +## [8.2.0.11](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.11) (2017-07-07) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1264...8.2.0.11) + +**Closed issues:** + +- config-rvd.sh bash syntax error [\#2328](https://github.com/RestComm/Restcomm-Connect/issues/2328) + +**Merged pull requests:** + +- \#2274: Child actors should be created using getContext\(\).actorOf\(\) [\#2323](https://github.com/RestComm/Restcomm-Connect/pull/2323) ([agafox](https://github.com/agafox)) + +## [8.2.0.1264](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1264) (2017-07-06) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1263...8.2.0.1264) + +**Closed issues:** + +- Call actor on Stopping state, don't block waiting for MmsCallController response [\#2261](https://github.com/RestComm/Restcomm-Connect/issues/2261) + +## [8.2.0.1263](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1263) (2017-07-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1262...8.2.0.1263) + +**Closed issues:** + +- MGCP Link Test [\#2319](https://github.com/RestComm/Restcomm-Connect/issues/2319) +- css for elements of the "take a tour feature" [\#2318](https://github.com/RestComm/Restcomm-Connect/issues/2318) +- Calls not removed from memory even after completing [\#2313](https://github.com/RestComm/Restcomm-Connect/issues/2313) +- If a conference is stopping and a new person wants to join it RC should start a new conference [\#2312](https://github.com/RestComm/Restcomm-Connect/issues/2312) + +## [8.2.0.1262](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1262) (2017-07-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1261...8.2.0.1262) + +**Closed issues:** + +- Add MEDIA\_MAX\_DURATION in the bin/restcomm/mediaserver.conf [\#2317](https://github.com/RestComm/Restcomm-Connect/issues/2317) +- add DTMF\_DETECTOR\_TONE\_INTERVAL at the bin/restcomm/mediaserver.conf [\#2303](https://github.com/RestComm/Restcomm-Connect/issues/2303) + +## [8.2.0.1261](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1261) (2017-07-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1260...8.2.0.1261) + +**Merged pull requests:** + +- Issue 2312 [\#2316](https://github.com/RestComm/Restcomm-Connect/pull/2316) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1260](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1260) (2017-07-04) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1259...8.2.0.1260) + +**Merged pull requests:** + +- Update Olympus configuration script to XML config file [\#2309](https://github.com/RestComm/Restcomm-Connect/pull/2309) ([ammendonca](https://github.com/ammendonca)) + +## [8.2.0.1259](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1259) (2017-07-03) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.BUG1014.82...8.2.0.1259) + +**Closed issues:** + +- Enpoint should send back feedback on unsuccessful response of DLCX [\#2310](https://github.com/RestComm/Restcomm-Connect/issues/2310) + +**Merged pull requests:** + +- Issue 2310 [\#2314](https://github.com/RestComm/Restcomm-Connect/pull/2314) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.BUG1014.82](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.BUG1014.82) (2017-07-03) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1258...8.2.0.BUG1014.82) + +## [8.2.0.1258](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1258) (2017-06-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1257...8.2.0.1258) + +## [8.2.0.1257](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1257) (2017-06-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1256...8.2.0.1257) + +**Closed issues:** + +- Play verb, support URL that don't point to wav files [\#2308](https://github.com/RestComm/Restcomm-Connect/issues/2308) +- Power Off Media Gateway throughs exception [\#2306](https://github.com/RestComm/Restcomm-Connect/issues/2306) + +## [8.2.0.1256](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1256) (2017-06-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1255...8.2.0.1256) + +**Closed issues:** + +- VoiceInterpreter callback doesn't execute when timedout call completed [\#2301](https://github.com/RestComm/Restcomm-Connect/issues/2301) +- Reconsider PR \#2268 with regards to the use of relative rcmlUrl for RVD apps [\#2295](https://github.com/RestComm/Restcomm-Connect/issues/2295) + +## [8.2.0.1255](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1255) (2017-06-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1254...8.2.0.1255) + +**Closed issues:** + +- B2BUAHelper when forwarding responses add User part in the Contact header of the cloned response, only if exists in the linkedResponse [\#2288](https://github.com/RestComm/Restcomm-Connect/issues/2288) +- Client's mock-ups in InVision [\#2285](https://github.com/RestComm/Restcomm-Connect/issues/2285) +- Number's registration mock-ups in InVision [\#2284](https://github.com/RestComm/Restcomm-Connect/issues/2284) +- create html css mock-ups for edit contact [\#2242](https://github.com/RestComm/Restcomm-Connect/issues/2242) +- Mock-up of the main page of the Console. Including users dropdown [\#2222](https://github.com/RestComm/Restcomm-Connect/issues/2222) +- Finalise Console's mock-ups [\#2119](https://github.com/RestComm/Restcomm-Connect/issues/2119) + +**Merged pull requests:** + +- Issue2212 rcmlserver baseurl configuration [\#2268](https://github.com/RestComm/Restcomm-Connect/pull/2268) ([otsakir](https://github.com/otsakir)) +- Added RVD configuration script for video options [\#2136](https://github.com/RestComm/Restcomm-Connect/pull/2136) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1254](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1254) (2017-06-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1253...8.2.0.1254) + +## [8.2.0.1253](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1253) (2017-06-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1252...8.2.0.1253) + +**Closed issues:** + +- Restcomm as Proxy [\#2286](https://github.com/RestComm/Restcomm-Connect/issues/2286) + +## [8.2.0.1252](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1252) (2017-06-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1251...8.2.0.1252) + +**Merged pull requests:** + +- Fixes \#2037 and \#2039 [\#2227](https://github.com/RestComm/Restcomm-Connect/pull/2227) ([nguyenhien1807](https://github.com/nguyenhien1807)) + +## [8.2.0.1251](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1251) (2017-06-26) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1250...8.2.0.1251) + +**Closed issues:** + +- PR\#1727 discussion with Gui [\#2235](https://github.com/RestComm/Restcomm-Connect/issues/2235) +- Unplanned work for `George 8.2.0 Sprint 4` [\#2203](https://github.com/RestComm/Restcomm-Connect/issues/2203) +- George's Sprint 4 - Customer support epic [\#2199](https://github.com/RestComm/Restcomm-Connect/issues/2199) + +## [8.2.0.1250](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1250) (2017-06-23) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1249...8.2.0.1250) + +**Closed issues:** + +- Fail call if SDP negotiation on RE-Invite fails [\#2272](https://github.com/RestComm/Restcomm-Connect/issues/2272) +- Customer ticket 34406 [\#2267](https://github.com/RestComm/Restcomm-Connect/issues/2267) +- Cloud incident [\#2231](https://github.com/RestComm/Restcomm-Connect/issues/2231) +- Paging Capabilities for IncomingPhoneNumbers API [\#2189](https://github.com/RestComm/Restcomm-Connect/issues/2189) +- Upgrade to Media Server 6.0 [\#1821](https://github.com/RestComm/Restcomm-Connect/issues/1821) +- Client Friendly Name is not effected. [\#1777](https://github.com/RestComm/Restcomm-Connect/issues/1777) + +**Merged pull requests:** + +- Issue 2171 From header imrovement in IMS calls [\#2277](https://github.com/RestComm/Restcomm-Connect/pull/2277) ([MarekSzalusOvoo](https://github.com/MarekSzalusOvoo)) +- Fix Friendly name not updated in case of register new client \#1777 [\#2266](https://github.com/RestComm/Restcomm-Connect/pull/2266) ([muhammadbilal19](https://github.com/muhammadbilal19)) + +## [8.2.0.1249](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1249) (2017-06-22) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1248...8.2.0.1249) + +**Closed issues:** + +- Update Acapela TTS account to paid version and create test script [\#2264](https://github.com/RestComm/Restcomm-Connect/issues/2264) +- Need to change name of query param in IncomingPhoneNumbersEndpoint [\#2243](https://github.com/RestComm/Restcomm-Connect/issues/2243) +- Video-RCML-Sprint2-Customer-Work [\#2226](https://github.com/RestComm/Restcomm-Connect/issues/2226) +- Contributing.md \(?\) [\#2182](https://github.com/RestComm/Restcomm-Connect/issues/2182) + +**Merged pull requests:** + +- Issue2230 configurable cors headers [\#2253](https://github.com/RestComm/Restcomm-Connect/pull/2253) ([otsakir](https://github.com/otsakir)) +- Moved Contributor's guide from the wiki page, to the project root [\#2188](https://github.com/RestComm/Restcomm-Connect/pull/2188) ([gsaslis](https://github.com/gsaslis)) + +## [8.2.0.1248](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1248) (2017-06-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1247...8.2.0.1248) + +**Closed issues:** + +- Update Android SDK Quick Start documentation [\#2247](https://github.com/RestComm/Restcomm-Connect/issues/2247) + +**Merged pull requests:** + +- Fixed \#2247: Update Android SDK Quick Start documentation [\#2248](https://github.com/RestComm/Restcomm-Connect/pull/2248) ([atsakiridis](https://github.com/atsakiridis)) + +## [8.2.0.1247](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1247) (2017-06-19) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1246...8.2.0.1247) + +**Closed issues:** + +- Items per page button selection doesn't shows as selected on Logs tabs [\#2232](https://github.com/RestComm/Restcomm-Connect/issues/2232) + +**Merged pull requests:** + +- Change query param name from PageSize to SortType.\#2243 [\#2244](https://github.com/RestComm/Restcomm-Connect/pull/2244) ([muhammadbilal19](https://github.com/muhammadbilal19)) +- Fixed Items per page button selection problem for logs tab \#2232 [\#2240](https://github.com/RestComm/Restcomm-Connect/pull/2240) ([muhammadbilal19](https://github.com/muhammadbilal19)) + +## [8.2.0.1246](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1246) (2017-06-15) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1245...8.2.0.1246) + +**Merged pull requests:** + +- Merge last commited changes for \#2189 [\#2238](https://github.com/RestComm/Restcomm-Connect/pull/2238) ([muhammadbilal19](https://github.com/muhammadbilal19)) +- Revert PR for "issue \#2189" [\#2237](https://github.com/RestComm/Restcomm-Connect/pull/2237) ([gvagenas](https://github.com/gvagenas)) +- issue \#2189 [\#2211](https://github.com/RestComm/Restcomm-Connect/pull/2211) ([muhammadbilal19](https://github.com/muhammadbilal19)) + +## [8.2.0.1245](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1245) (2017-06-15) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1244...8.2.0.1245) + +**Closed issues:** + +- Restcomm CI job fails [\#2236](https://github.com/RestComm/Restcomm-Connect/issues/2236) +- Remove the yellow color [\#2038](https://github.com/RestComm/Restcomm-Connect/issues/2038) + +**Merged pull requests:** + +- Issue2178 better downloader logging [\#2213](https://github.com/RestComm/Restcomm-Connect/pull/2213) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1244](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1244) (2017-06-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1243...8.2.0.1244) + +## [8.2.0.1243](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1243) (2017-06-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_Voice2b.80...8.2.0.1243) + +**Closed issues:** + +- RCML Downloader logging does not provide adequate information [\#2178](https://github.com/RestComm/Restcomm-Connect/issues/2178) +- Support CORS request filtering [\#2163](https://github.com/RestComm/Restcomm-Connect/issues/2163) + +**Merged pull requests:** + +- RESTCOM-884 : Implement Multiprovider Voice 2b [\#2191](https://github.com/RestComm/Restcomm-Connect/pull/2191) ([abdulazizali77](https://github.com/abdulazizali77)) +- WIP Voice Proposal 2b [\#2138](https://github.com/RestComm/Restcomm-Connect/pull/2138) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.0.MPROV_Voice2b.80](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_Voice2b.80) (2017-06-13) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_Voice2b.79...8.2.0.MPROV_Voice2b.80) + +**Closed issues:** + +- Change the color of numbers [\#2039](https://github.com/RestComm/Restcomm-Connect/issues/2039) +- Change the logo to Restcomm Console [\#2037](https://github.com/RestComm/Restcomm-Connect/issues/2037) +- move Default Welcome RVD message to configuration file [\#1605](https://github.com/RestComm/Restcomm-Connect/issues/1605) + +## [8.2.0.MPROV_Voice2b.79](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_Voice2b.79) (2017-06-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_Voice2b.78...8.2.0.MPROV_Voice2b.79) + +## [8.2.0.MPROV_Voice2b.78](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_Voice2b.78) (2017-06-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_Voice2b.77...8.2.0.MPROV_Voice2b.78) + +**Closed issues:** + +- OutboundProxy API should be accessible by super admin only [\#2210](https://github.com/RestComm/Restcomm-Connect/issues/2210) +- Update Calls API docs for the Dial status callback [\#2208](https://github.com/RestComm/Restcomm-Connect/issues/2208) +- Update IncomingPhoneNumbers API docs for the status callback feature [\#2207](https://github.com/RestComm/Restcomm-Connect/issues/2207) +- GatewaysEndpoint should be only accessible by super admin [\#2204](https://github.com/RestComm/Restcomm-Connect/issues/2204) +- IncomingPhoneNumber REGEX match fails for 5555|4444 [\#2197](https://github.com/RestComm/Restcomm-Connect/issues/2197) +- Review SipServlets Graceful Shutdown feature [\#2196](https://github.com/RestComm/Restcomm-Connect/issues/2196) +- What do we open architecture diagrams with? [\#2181](https://github.com/RestComm/Restcomm-Connect/issues/2181) +- MGCP: When Call actor receives CANCEL on inbound call before MS has send respond to CRCX, Connect tries to remove all endpoints [\#2180](https://github.com/RestComm/Restcomm-Connect/issues/2180) +- Use configurable rvd location in Dashboard templates [\#2177](https://github.com/RestComm/Restcomm-Connect/issues/2177) +- Properly handle exceptions in server-side password-validation [\#2175](https://github.com/RestComm/Restcomm-Connect/issues/2175) +- Issue \#1981: MultiProvider RC and Extensions API implementation: redundant code in SmsService and SmmpMessageHandler [\#2123](https://github.com/RestComm/Restcomm-Connect/issues/2123) +- Typo! [\#1809](https://github.com/RestComm/Restcomm-Connect/issues/1809) +- Migrate http://docs.telestax.com/restcomm-docker-quick-start-guide/ to asciidoc [\#1086](https://github.com/RestComm/Restcomm-Connect/issues/1086) + +**Merged pull requests:** + +- Issue2175 js password validation error logging [\#2214](https://github.com/RestComm/Restcomm-Connect/pull/2214) ([otsakir](https://github.com/otsakir)) +- Add warning about outdated architecture diagrams [\#2200](https://github.com/RestComm/Restcomm-Connect/pull/2200) ([gsaslis](https://github.com/gsaslis)) + +## [8.2.0.MPROV_Voice2b.77](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_Voice2b.77) (2017-06-06) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1241...8.2.0.MPROV_Voice2b.77) + +**Closed issues:** + +- Olympus text box change place while calling [\#2147](https://github.com/RestComm/Restcomm-Connect/issues/2147) +- Conference perf job fails [\#2116](https://github.com/RestComm/Restcomm-Connect/issues/2116) +- Requirements and Design document for CDR refactoring [\#2060](https://github.com/RestComm/Restcomm-Connect/issues/2060) +- UserAgentManager actor restarts on NPE after ApplicationSession invalidate\(\) [\#1764](https://github.com/RestComm/Restcomm-Connect/issues/1764) +- Support transition for Account auth token [\#1491](https://github.com/RestComm/Restcomm-Connect/issues/1491) + +## [8.2.0.1241](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1241) (2017-06-01) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1240...8.2.0.1241) + +**Closed issues:** + +- IncomingPhoneNumbersDao: Improve REGEX check [\#2179](https://github.com/RestComm/Restcomm-Connect/issues/2179) +- Make Dashboard links to RVD configurable through dashboard.json [\#2174](https://github.com/RestComm/Restcomm-Connect/issues/2174) + +## [8.2.0.1240](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1240) (2017-05-30) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1239...8.2.0.1240) + +## [8.2.0.1239](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1239) (2017-05-29) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1238...8.2.0.1239) + +**Closed issues:** + +- Update RCML documentation including whats new for video [\#2149](https://github.com/RestComm/Restcomm-Connect/issues/2149) +- Update TADHack environment for Restconn [\#2130](https://github.com/RestComm/Restcomm-Connect/issues/2130) +- Missing configuration when using docker [\#2055](https://github.com/RestComm/Restcomm-Connect/issues/2055) +- Conference participants have no audio when using XMS [\#1645](https://github.com/RestComm/Restcomm-Connect/issues/1645) +- Making a video call from tadhack olympus to +1235 fails [\#1477](https://github.com/RestComm/Restcomm-Connect/issues/1477) + +**Merged pull requests:** + +- fixed zendesk\#34319 [\#2172](https://github.com/RestComm/Restcomm-Connect/pull/2172) ([anhntnguyen](https://github.com/anhntnguyen)) + +## [8.2.0.1238](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1238) (2017-05-22) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_Voice2b.9...8.2.0.1238) + +**Closed issues:** + +- Response to outbound SMS never reach the client that initiated the message [\#2166](https://github.com/RestComm/Restcomm-Connect/issues/2166) +- Support for Java 8? [\#2161](https://github.com/RestComm/Restcomm-Connect/issues/2161) +- RC rest api return 200 OK to new client addition even if client with same name exist [\#2160](https://github.com/RestComm/Restcomm-Connect/issues/2160) + +## [8.2.0.MPROV_Voice2b.9](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_Voice2b.9) (2017-05-18) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1237...8.2.0.MPROV_Voice2b.9) + +**Closed issues:** + +- Unplanned work for `George 8.2.0 Sprint 2` [\#2120](https://github.com/RestComm/Restcomm-Connect/issues/2120) + +## [8.2.0.1237](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1237) (2017-05-17) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1236...8.2.0.1237) + +**Closed issues:** + +- CallManager properly handle numbers that start with + [\#2158](https://github.com/RestComm/Restcomm-Connect/issues/2158) +- Outbound call never reach the completed state when inbound call sends BYE [\#2157](https://github.com/RestComm/Restcomm-Connect/issues/2157) + +## [8.2.0.1236](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1236) (2017-05-15) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1235...8.2.0.1236) + +**Closed issues:** + +- MonitoringService should return a link to Calls API to get the list of active calls instead of return an array of call details [\#1453](https://github.com/RestComm/Restcomm-Connect/issues/1453) + +**Merged pull requests:** + +- fix null variable that prevents Regex from working [\#2151](https://github.com/RestComm/Restcomm-Connect/pull/2151) ([croufay](https://github.com/croufay)) + +## [8.2.0.1235](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1235) (2017-05-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1234...8.2.0.1235) + +## [8.2.0.1234](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1234) (2017-05-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1233...8.2.0.1234) + +## [8.2.0.1233](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1233) (2017-05-12) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.issue2130.8...8.2.0.1233) + +## [8.2.0.issue2130.8](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.issue2130.8) (2017-05-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.issue2130.7...8.2.0.issue2130.8) + +## [8.2.0.issue2130.7](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.issue2130.7) (2017-05-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1232...8.2.0.issue2130.7) + +**Closed issues:** + +- Properly clean up CANCELED outgoing calls [\#2139](https://github.com/RestComm/Restcomm-Connect/issues/2139) + +**Merged pull requests:** + +- increased column length [\#2142](https://github.com/RestComm/Restcomm-Connect/pull/2142) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1232](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1232) (2017-05-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1231...8.2.0.1232) + +## [8.2.0.1231](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1231) (2017-05-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1230...8.2.0.1231) + +## [8.2.0.1230](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1230) (2017-05-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1229...8.2.0.1230) + +**Closed issues:** + +- RC does not not stop MOH for XMS media server [\#2137](https://github.com/RestComm/Restcomm-Connect/issues/2137) +- Properly clean up BUSY Outgoing calls [\#2135](https://github.com/RestComm/Restcomm-Connect/issues/2135) + +**Merged pull requests:** + +- patched \#2137 [\#2140](https://github.com/RestComm/Restcomm-Connect/pull/2140) ([maria-farooq](https://github.com/maria-farooq)) + +## [8.2.0.1229](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1229) (2017-05-10) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1227...8.2.0.1229) + +**Closed issues:** + +- ExtensionsConfiguration REST API wrong json response on getConfiguration\(\) [\#2134](https://github.com/RestComm/Restcomm-Connect/issues/2134) + +## [8.2.0.1227](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1227) (2017-05-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1226...8.2.0.1227) + +**Merged pull requests:** + +- Issue \#1981: WIP MultiProvider RC extension [\#2007](https://github.com/RestComm/Restcomm-Connect/pull/2007) ([abdulazizali77](https://github.com/abdulazizali77)) + +## [8.2.0.1226](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1226) (2017-05-09) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.issue2130.5...8.2.0.1226) + +## [8.2.0.issue2130.5](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.issue2130.5) (2017-05-08) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1225...8.2.0.issue2130.5) + +**Closed issues:** + +- Update TADHack cloud environment [\#1945](https://github.com/RestComm/Restcomm-Connect/issues/1945) +- Video conferencing - RCML [\#1552](https://github.com/RestComm/Restcomm-Connect/issues/1552) + +**Merged pull requests:** + +- Issue\#708 Add PhoneNumber Regex for SMS/Voice and USSD [\#1806](https://github.com/RestComm/Restcomm-Connect/pull/1806) ([croufay](https://github.com/croufay)) + +## [8.2.0.1225](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1225) (2017-05-05) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1223...8.2.0.1225) + +**Closed issues:** + +- monitoringservice metrics for registered users should distinctly identify users of all organizations [\#2128](https://github.com/RestComm/Restcomm-Connect/issues/2128) +- Race condition that prevents inbound Call actors clean up when using LCM [\#2117](https://github.com/RestComm/Restcomm-Connect/issues/2117) +- Unplanned work for George's 8.2.0 sprint 1 [\#2104](https://github.com/RestComm/Restcomm-Connect/issues/2104) + +## [8.2.0.1223](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1223) (2017-04-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1222...8.2.0.1223) + +## [8.2.0.1222](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1222) (2017-04-28) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1221...8.2.0.1222) + +**Closed issues:** + +- ACK RURI from call actor, should contain the user part of the original RURI [\#2111](https://github.com/RestComm/Restcomm-Connect/issues/2111) + +## [8.2.0.1221](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1221) (2017-04-27) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1220...8.2.0.1221) + +**Closed issues:** + +- SmsSession support for To=client:alice [\#2108](https://github.com/RestComm/Restcomm-Connect/issues/2108) + +## [8.2.0.1220](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1220) (2017-04-26) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1219...8.2.0.1220) + +**Closed issues:** + +- Dial with record=true test cases are failing [\#2103](https://github.com/RestComm/Restcomm-Connect/issues/2103) + +## [8.2.0.1219](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1219) (2017-04-26) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_1981.9...8.2.0.1219) + +**Closed issues:** + +- Apply mock-ups [\#2080](https://github.com/RestComm/Restcomm-Connect/issues/2080) + +## [8.2.0.MPROV_1981.9](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_1981.9) (2017-04-26) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1217...8.2.0.MPROV_1981.9) + +## [8.2.0.1217](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1217) (2017-04-25) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1216...8.2.0.1217) + +**Closed issues:** + +- mute unmute a call [\#1957](https://github.com/RestComm/Restcomm-Connect/issues/1957) +- Add functionality to mute/unmute conference participants [\#1135](https://github.com/RestComm/Restcomm-Connect/issues/1135) + +## [8.2.0.1216](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1216) (2017-04-24) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_1981.8...8.2.0.1216) + +**Closed issues:** + +- Add new parameter to pass JVM setting for load test scripts [\#2088](https://github.com/RestComm/Restcomm-Connect/issues/2088) +- RestComm build process overwrites MGCP driver dependency [\#2015](https://github.com/RestComm/Restcomm-Connect/issues/2015) +- CDR resulting from sub-account-client inbound calls has parent 'accountSid' [\#1939](https://github.com/RestComm/Restcomm-Connect/issues/1939) + +## [8.2.0.MPROV_1981.8](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_1981.8) (2017-04-24) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1215...8.2.0.MPROV_1981.8) + +## [8.2.0.1215](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1215) (2017-04-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1214...8.2.0.1215) + +## [8.2.0.1214](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1214) (2017-04-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1213...8.2.0.1214) + +**Merged pull requests:** + +- Revert SMPP SMS encoding to GSM. And use -d encoding for API. [\#2091](https://github.com/RestComm/Restcomm-Connect/pull/2091) ([leftyb](https://github.com/leftyb)) + +## [8.2.0.1213](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1213) (2017-04-21) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_1981.7...8.2.0.1213) + +**Closed issues:** + +- George 8.2.0 Sprint 1 [\#2087](https://github.com/RestComm/Restcomm-Connect/issues/2087) +- Support dialling a registered client if request comes from external network [\#2086](https://github.com/RestComm/Restcomm-Connect/issues/2086) +- Default organization’s domain\_name in organization table will be picked from RC hostname on bootstrap. [\#2085](https://github.com/RestComm/Restcomm-Connect/issues/2085) +- Add OPS functionality in RC binary. [\#2082](https://github.com/RestComm/Restcomm-Connect/issues/2082) + +## [8.2.0.MPROV_1981.7](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_1981.7) (2017-04-20) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1212...8.2.0.MPROV_1981.7) + +**Closed issues:** + +- Automatic configuration script failing during bootstrap [\#2069](https://github.com/RestComm/Restcomm-Connect/issues/2069) + +## [8.2.0.1212](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1212) (2017-04-18) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1211...8.2.0.1212) + +**Merged pull requests:** + +- Issue2069 rvdconfig failure [\#2071](https://github.com/RestComm/Restcomm-Connect/pull/2071) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1211](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1211) (2017-04-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.MPROV_1981.6...8.2.0.1211) + +## [8.2.0.MPROV_1981.6](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.MPROV_1981.6) (2017-04-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.5...8.2.0.MPROV_1981.6) + +## [8.2.0.5](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.5) (2017-04-14) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1210...8.2.0.5) + +**Closed issues:** + +- GUI: sometimes, numbers stop showing [\#2056](https://github.com/RestComm/Restcomm-Connect/issues/2056) +- When using the Usage API the uri field in response contains /todo.jsp [\#1689](https://github.com/RestComm/Restcomm-Connect/issues/1689) + +## [8.2.0.1210](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1210) (2017-04-13) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/8.2.0.1209...8.2.0.1210) + +**Closed issues:** + +- Unplanned Support Work for 8.1.0 - Epic [\#1948](https://github.com/RestComm/Restcomm-Connect/issues/1948) +- Load tests for 8.1.0 [\#1922](https://github.com/RestComm/Restcomm-Connect/issues/1922) +- Dial Conference load test for 8.1.0 [\#1917](https://github.com/RestComm/Restcomm-Connect/issues/1917) + +**Merged pull requests:** + +- Designer issue120 logging configuration [\#2057](https://github.com/RestComm/Restcomm-Connect/pull/2057) ([otsakir](https://github.com/otsakir)) + +## [8.2.0.1209](https://github.com/RestComm/Restcomm-Connect/tree/8.2.0.1209) (2017-04-11) +[Full Changelog](https://github.com/RestComm/Restcomm-Connect/compare/810ga...8.2.0.1209) + +**Closed issues:** + +- Add rvd logging configuration to standalone-sip.xml [\#2052](https://github.com/RestComm/Restcomm-Connect/issues/2052) +- Create Call REST API load test for 8.1.0 [\#1921](https://github.com/RestComm/Restcomm-Connect/issues/1921) +- Gather load test for 8.1.0 [\#1920](https://github.com/RestComm/Restcomm-Connect/issues/1920) +- Play one minute announcement load test for 8.1.0 [\#1919](https://github.com/RestComm/Restcomm-Connect/issues/1919) +- Dial Client load test for 8.1.0 [\#1918](https://github.com/RestComm/Restcomm-Connect/issues/1918) +- For some cases under heavy load CompletedCalls counter is bigger than the IncomingCalls counter [\#1679](https://github.com/RestComm/Restcomm-Connect/issues/1679) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/CONTRIBUTING.asciidoc b/CONTRIBUTING.asciidoc new file mode 100644 index 0000000000..8ddee22ffe --- /dev/null +++ b/CONTRIBUTING.asciidoc @@ -0,0 +1,282 @@ += Contribute to Restcomm + +Multiple types of contributions are possible : + + * Using it in your product or project and providing feedback. + * Code & Algorithms: Core Projects, Incubator projects, Frameworks + * Use cases, feature requests: Roadmap influence + * Community Support, bug fixes, forum posts: Help to be helped + * Documentation: Everyone needs good docs, Code is a moving targed. + * Testing (Perf, load, security, unit tests, interop, ...) / CI + +Here is specific types of contributions that requires a little more details if you want to get involved + + * Fixing Bugs : See https://help.github.com/articles/closing-issues-via-commit-messages + * Reporting Bugs : To report a bug, if possible, provide a small example that illustrates the bug. You can pattern + the test case usually along the lines of ones found in the + link:https://github.com/Restcomm/Restcomm-Connect/tree/master/restcomm/restcomm.testsuite[testsuite]. + Having a test case handy speeds up the bug fix. Your test case will be included in the project as a test case. + Open an Issue as defined in the section below so other users can know about the issue and its status. + Please attach your test case or bug description with debug log files there. + * Contributing Extensions and enhancements (i.e. support for extension RFCs and drafts that are not covered by + Restcomm) or Contributing code snippets and examples or Contributing test cases to be included with the + distribution: See Contribution Process below in Section "How to check out, change, review, and commit code". + Also open a thread on link:http://groups.google.com/group/restcomm[the mailing list of Restcomm google group] + to discuss it with the community and Restcomm Team Members. + +Your contributions will be acknowledged individually in the code (as a comment) and in the +link:http://www.telestax.com/opensource/#Contribute[Acknowledgement page]. + + += Opening an Issue + +link:https://github.com/Restcomm/Restcomm-Connect/issues/new[Open An Issue Here] + += Becoming a Contributor + +In order to become a contributor with write access to the code, you will need to have demonstrated an understanding +of the codebase and testsuite by participating in the design discussions and submitting patches for bugs/enchancements +before we will grant developer access. + +Contributing to Restcomm requires you to accept link:http://telestax.com/opensource/[the TeleStax Contributor Agreement] +(bottom of the page). + += How to check out, change, review, and commit code +== Introduction + +Restcomm projects use Git, a distributed version control system. What this means is that, even though this page hosts +a central repository, there can be many clone repositories with changes of their own, and then some of those can be +merged back into the main repository. + +*The great part is that you can start contributing and create our own clone without having write access to the +Restcomm repository* + +This document describes the workflow for checking out code, making clones, reviewing patches, and committing code. + +== Checking out Restcomm Connect (Linux) + +For non-committers, checking out code is simple. + +=== Install Git + +Follow the installing Git instructions. Ubuntu users can simply type: + +[source,bash] +---- +sudo apt-get install git-core +---- + +Configure Git to convert line endings on commit + +[source,bash] +---- +git config --global core.autocrlf input +---- + +=== Checkout the code + +To check out the code : + +[source,bash] +---- +git clone git@github.com:Restcomm/Restcomm-Connect.git +---- + + +=== Building Restcomm From Source +To Build Restcomm from Source, follow those instructions : http://docs.telestax.com/restcomm-mobicents-building-from-source/ + + +=== Committing code + +The following License Header has to be placed on top of each source code file contributed + +[source,java] +---- +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, 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 + * + */ +---- + +The model we've chosen for developing Restcomm is the following: + +Each contributor creates their own fork of the Restcomm project (you want to contribute to) repository. + +This clone is hosted on Github servers, and can be created by clicking *Fork* button from +https://github.com/Restcomm/Restcomm-Connect + +The contributor then makes a local clone of their GitHub fork, which is stored on their local machine. +Instructions for checking it out is https://github.com//Restcomm + +The contributor creates a new Issue explaining their contribution at +https://github.com/Restcomm/Restcomm-Connect/issues/new + +The contributor then creates a new branch into their local clone + +[source,bash] +---- +git checkout -b feature-branch +---- + +Do the changes into their branch for their local branch for the contribution and commit them + +[source,bash] +---- +git commit -a -m "commit message" +---- + +**//IMPORTANT//:Please use the Github integration to use the commit message to tie the commits to the Issue you're +working on. More information on that can be found at https://help.github.com/articles/closing-issues-via-commit-messages** + +**//IMPORTANT//: When your change is pulled into the main Restcomm source, the change description that you entered here + will show up as changes in the main Restcomm source, so please use a meaningful description - fixing bug, making + changes, etc. are not ok, please instead use something like fixing transform bug caused by NPE, etc. so that it makes + sense in the context of Restcomm as a whole, not just your clone.** + +If you have any new files, make sure to use the following command before committing + +[source,bash] +---- +git add +---- + +Same thing if you want to remove some files + +[source,bash] +---- +git rm +---- + +== Pushing changes to your online clone + +When a change is ready to be integrated back into the repository, that change is pushed from the developer's local +clone to their Github Fork clone. + +[source,bash] +---- +git push origin feature-branch +---- + +To avoid merge soup, please rebase your branch first + +==== Bringing in new changes from the upstream repository + +If the main repository has evolved since your last push to your clone repository, you will need to bring those changes +into your repository as well as potentially merge them. + +You need to add a remote via which you will identify the upstream repository: + +[source,bash] +---- +git remote add upstream git@github.com:Restcomm/Restcomm-Connect.git +---- + +Now whenever you want to merge upstream changes into your clone, do the following: + +[source,bash] +---- +git fetch upstream +git merge upstream/master +---- + +==== Pushing changes to your clone repository + +First pull in all of the latest changes from upstream, apply them to your master branch, then rebase your feature +branch against master before merging it into master and pushing it upstream: + +[source,bash] +---- +git checkout master +git fetch upstream +git merge upstream/master +git checkout awesome-feature +git rebase master +(fix any conflicts with upstream changes) +git push origin feature-branch +---- + +Browse to Source -> Changes from the project page for your clone and navigate to the page with details on the branch +to be reviewed. For example, https://github.com//Restcomm/tree/development + +You will need to paste the URL for this page into the issue you created earlier. +Describe the code to be reviewed, its purpose, and paste in the URL for the relevant changeset(s) or branch(es). + +The code will be reviewed on the contributor's clone - if any further changes are suggested, a couple of iterations +might be needed so the contributor will need to modify the code again, commit, push and comment on the issue. + +Once the change is approved, a committer of Restcomm will merge it back into the main repository with the following +commands. + +[source,bash] +---- +git checkout -b feature-branch +git pull https://github.com//Restcomm/ feature-branch +git checkout master +git merge feature-branch +---- + +Even though this may sound complicated, this process makes code reviews easier and allows a lot of people to work on +changes in parallel. + +==== Code formatting + +In order to avoid merge conflicts, be it with new features or bug fixes, Restcomm takes advantage of maven code +formatting plugin. By default, all of our projects trigger this plugin during build. It provides information on code +style and violations of certain rules. +Example failure may look as follows: + +[source,bash] +---- +[INFO] Starting audit... +/home/baranowb/Restcomm/git/test/src/main/java/Test.java:46: Line has trailing spaces. +/home/baranowb/Restcomm/git/test/src/main/java/Test.java:47:1: '{' should be on the previous line. +/home/baranowb/Restcomm/git/test/src/main/java/Test.java:50: Line has trailing spaces. +Audit done. +---- + +Contributor responsibility is to provide us with code, which obeys formatting rules. If source does not pass code +style checks, it won't be accepted! + +===== IDE formatting support + +IDEs have native support for formatting. To take advantage of it, you need to import configuration files. +Restcomm has projects wide configuration for IDEs. It can be found here: +http://grepcode.com/snapshot/repo1.maven.org/maven2/org.mobicents/checkstyle/1.0.0.FINAL/ +or in any tagged relase of this artifact. + +===== Eclipse +To import formatter rules into eclipse perform following: + + * Window > Preferences > Java > Code Style > Clean Up > 'Import' -> cleanup.xml + * Window > Preferences > Java > Code Style > Formatter > 'Import' -> formatter.xml + +Optionally: + * Window > Preferences > Java > Code Style > Code Templates > 'Import' -> templates.xml + +===== Maven checkstyle configuration + +The checkstyle plugin is pre-configured in mobicents-parent artifact. To enable it in any subproject which depends on it, you need to add only following lines in *plugins* section of master project pom: + +[source,xml] +---- + + org.apache.maven.plugins + maven-checkstyle-plugin + +---- \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000..416a8d3e00 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,61 @@ + +def runTestsuite(exludedGroups = "org.restcomm.connect.commons.annotations.BrokenTests",groups = "", forkCount=1, profile="") { + sh "mvn -f restcomm/restcomm.testsuite/pom.xml install -DskipUTs=false -Dmaven.test.failure.ignore=true -Dmaven.test.redirectTestOutputToFile=true -Dfailsafe.rerunFailingTestsCount=1 -Dgroups=\"$groups\" -DexcludedGroups=\"$exludedGroups\"" +} + + +def buildRC() { + // Run the maven build with in-module unit testing and sonar + try { + if (env.BRANCH_NAME == 'master') { + //do sonar just in master + sh "mvn -f restcomm/pom.xml -pl \\!restcomm.testsuite -Dmaven.test.redirectTestOutputToFile=true -Dsonar.host.url=https://sonarqube.com -Dsonar.login=dd43f79a4bd32b1f2c484362e8a4de676a8388c4 -Dsonar.organization=jaimecasero-github -Dsonar.branch=master install sonar:sonar" + } else { + sh "mvn -f restcomm/pom.xml -pl \\!restcomm.testsuite -Dmaven.test.redirectTestOutputToFile=true install" + } + } catch(err) { + publishRCResults() + throw err + } +} + +def publishRCResults() { + junit testResults: '**/target/surefire-reports/*.xml', testDataPublishers: [[$class: 'StabilityTestDataPublisher']] + checkstyle canComputeNew: false, defaultEncoding: '', healthy: '', pattern: '**/checkstyle-result.xml', unHealthy: '' + step( [ $class: 'JacocoPublisher' ] ) + if ((env.BRANCH_NAME == 'master') && (currentBuild.currentResult != 'SUCCESS') ) { + slackSend "Build unstable - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)" + } +} + +node("cxs-ups-testsuites_large") { + + echo sh(returnStdout: true, script: 'env') + + configFileProvider( + [configFile(fileId: '37cb206e-6498-4d8a-9b3d-379cd0ccd99b', targetLocation: 'settings.xml')]) { + sh 'mkdir -p ~/.m2 && sed -i "s|@LOCAL_REPO_PATH@|$WORKSPACE/M2_REPO|g" $WORKSPACE/settings.xml && cp $WORKSPACE/settings.xml -f ~/.m2/settings.xml' + } + + stage ('Checkout') { + checkout scm + } + + stage ("Build") { + buildRC() + } + + stage("CITestsuiteSeq") { + runTestsuite("org.restcomm.connect.commons.annotations.ParallelClassTests or org.restcomm.connect.commons.annotations.UnstableTests or org.restcomm.connect.commons.annotations.BrokenTests") + } + + + stage("CITestsuiteParallel") { + runTestsuite("org.restcomm.connect.commons.annotations.UnstableTests or org.restcomm.connect.commons.annotations.BrokenTests", "org.restcomm.connect.commons.annotations.ParallelClassTests", "20" , "parallel-testing") + } + + + stage("PublishResults") { + publishRCResults() + } +} diff --git a/README.md b/README.md index c74e9d3178..565d3879eb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ 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) The Open Source Cloud Communications Platform @@ -8,7 +9,7 @@ The Open Source Cloud Communications Platform What is RestComm ? ======== -Mobicents RestComm is a next generation Cloud Communications Platform. It allows web developers to rapidly build voice, video, WebRTC, USSD, SMS, fax and rich messaging applications. Restcomm opens new revenue streams for service providers by exposing existing SS7 and IMS core network assets to application developers. +RestComm is a next generation Cloud Communications Platform. It allows web developers to rapidly build voice, video, WebRTC, USSD, SMS, fax and rich messaging applications. Restcomm opens new revenue streams for service providers by exposing existing SS7 and IMS core network assets to application developers. Restcomm enables apps such as telehealth, group communication, in-game messaging, online experience sharing, interactive customer support and others. @@ -16,36 +17,46 @@ Telecom Application Development is within reach of only a small number of highly Restcomm is here to change that! Joining a wave of innovating companies and service providers, Restcomm brings common sense to the millions of web developers with an intuitive and powerful set of RESTful APIs. Read the Restcomm data sheet. -Ready to take Restcomm for a spin? [TRY IT NOW](https://aws.amazon.com/marketplace/pp/B00FFHJ6SU) on Amazon Marketplace. It only takes a few minutes to set it up and running. - Downloads ======== -[Get the latest release!](https://mobicents.ci.cloudbees.com/job/RestComm/lastSuccessfulBuild/artifact/) or [TRY IT NOW](https://aws.amazon.com/marketplace/pp/B00FFHJ6SU) on Amazon Marketplace. It only takes a few minutes to set it up and running. +Use [the Docker image](http://documentation.telestax.com/connect/configuration/docker/Restcomm%20-%20Docker%20Quick%20Start%20Guide.html#restcomm-docker/). It only takes a few minutes to set it up and running. +Alternatively, you can download the [Binary zip](https://www.restcomm.com/downloads/) as well Documentation ======== -Read the [Online RestComm Documentation](http://docs.telestax.com/) or it is also contained in the download binary +Read the [Online RestComm Documentation](http://documentation.telestax.com/connect/) or it is also contained in the download binary + +Want to Contribute ? +======== +[See our Contributors Guide](CONTRIBUTING.asciidoc) and [How to build RestComm From Source](http://docs.telestax.com/restcomm-mobicents-building-from-source/) and [![Join the chat at https://gitter.im/RestComm/Restcomm-Connect](https://badges.gitter.im/RestComm/Restcomm-Connect.svg)](https://gitter.im/RestComm/Restcomm-Connect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Issue Tracking and Roadmap ======== -[Issue Tracker](https://github.com/Mobicents/RestComm/issues) +[Issue Tracker](https://github.com/RestComm/RestComm-Core/issues) Questions ? ======== -Please ask your question on our [public forum](http://groups.google.com/group/restcomm) +Please ask your question on [StackOverflow](http://stackoverflow.com/questions/tagged/restcomm) or the Google [public forum](http://groups.google.com/group/restcomm) and [![Join the chat at https://gitter.im/RestComm/Restcomm-Connect](https://badges.gitter.im/RestComm/Restcomm-Connect.svg)](https://gitter.im/RestComm/Restcomm-Connect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + License ======== RestComm is lead by [TeleStax](http://www.telestax.com/), Inc. and developed collaboratively by a community of individual and enterprise contributors. -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)) +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](https://www.restcomm.com/contact/)) + +[![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) Continuous Integration and Delivery ======== -[![RestComm Continuous Job](http://www.cloudbees.com/sites/default/files/Button-Built-on-CB-1.png)](https://mobicents.ci.cloudbees.com/job/RestComm/) +[![RestComm Continuous Job]](https://cxs.restcomm.com/view/Restcomm/job/UPS_RestComm/) Acknowledgements ======== +Java Profiler sponsored by YourKit +[![YourKit The Industry Leader in .NET & Java Profiling](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/) + [See who has been contributing to RestComm](http://www.telestax.com/opensource/acknowledgments/) diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000000..fadccef740 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,41 @@ +## Support for deploying and using Restcomm + +Welcome to Restcomm! We use GitHub for tracking bugs and feature requests. +This isn't the right place to get support for using Restcomm, but there are other free resources you can use +for that, if you don't want to purchase one of the [Telestax commercial support packages](https://telestax.com/support/). + +Please help us better maintain these FOSS projects by following these guidelines and not raising help-related issues here. + +Thanks in advance for your understanding! + +### Stack Overflow + +The Restcomm Community is active on Stack Overflow, you can post your questions there: + +* [Restcomm on Stack Overflow](http://stackoverflow.com/questions/tagged/restcomm) + + * Here are some tips for [about how to ask good questions](http://stackoverflow.com/help/how-to-ask). + * Don't forget to check to see [what's on topic](http://stackoverflow.com/help/on-topic). + +### Mailing Lists / Groups + +You can find answers for older questions also in our +[[Mobicents-Public]](https://groups.google.com/forum/#!forum/mobicents-public) +and [[Restcomm]](https://groups.google.com/forum/#!forum/restcomm) mailing lists. + +**Please avoid raising new issues** in the mailing lists, as we will be migrating away from these soon. + +### Documentation + +* Documentation is available on the [Restcomm Site](https://www.restcomm.com/docs/) + + +### Real-time Chat + +* You can use the public [Restcomm Discuss Gitter channel](https://gitter.im/RestComm/Restcomm-discuss) for general issues. + + + + diff --git a/architecture_diagrams/README.asciidoc b/architecture_diagrams/README.asciidoc new file mode 100644 index 0000000000..83d8dccd75 --- /dev/null +++ b/architecture_diagrams/README.asciidoc @@ -0,0 +1,8 @@ += Restcomm Connect Architecture Diagrams + +WARNING: Some of the diagrams here are outdated and are pending an update. Once updated, they will also probably be +converted to a different format, so please don't worry too much about getting the below app (Dia Diagram Editor) +working on your machine to view these diagrams. + +This directory contains some architecture diagrams for Restcomm Connect. The application you can use for opening them is +found at http://dia-installer.de/. diff --git a/architecture_diagrams/interpreter.dia b/architecture_diagrams/interpreter.dia index 195115cdbc..8a6c04611e 100644 Binary files a/architecture_diagrams/interpreter.dia and b/architecture_diagrams/interpreter.dia differ diff --git a/architecture_diagrams/mscontrol/add-participant-flow.dia b/architecture_diagrams/mscontrol/add-participant-flow.dia new file mode 100644 index 0000000000..593c02b0c3 Binary files /dev/null and b/architecture_diagrams/mscontrol/add-participant-flow.dia differ diff --git a/architecture_diagrams/mscontrol/bridge-add-participant.dia b/architecture_diagrams/mscontrol/bridge-add-participant.dia new file mode 100644 index 0000000000..8618225852 Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge-add-participant.dia differ diff --git a/architecture_diagrams/mscontrol/bridge-classes.dia b/architecture_diagrams/mscontrol/bridge-classes.dia new file mode 100644 index 0000000000..4897aa1b5f Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge-classes.dia differ diff --git a/architecture_diagrams/mscontrol/bridge-mscontrol.dia b/architecture_diagrams/mscontrol/bridge-mscontrol.dia new file mode 100644 index 0000000000..39e8b96911 Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge-mscontrol.dia differ diff --git a/architecture_diagrams/mscontrol/bridge-sequence-new-proposal.dia b/architecture_diagrams/mscontrol/bridge-sequence-new-proposal.dia new file mode 100644 index 0000000000..de36eb2dfd Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge-sequence-new-proposal.dia differ diff --git a/architecture_diagrams/mscontrol/bridge-sequence.dia b/architecture_diagrams/mscontrol/bridge-sequence.dia new file mode 100644 index 0000000000..89cb2e9cf2 Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge-sequence.dia differ diff --git a/architecture_diagrams/mscontrol/bridge.dia b/architecture_diagrams/mscontrol/bridge.dia new file mode 100644 index 0000000000..8c9d9fb919 Binary files /dev/null and b/architecture_diagrams/mscontrol/bridge.dia differ diff --git a/architecture_diagrams/mscontrol/call-add-participant.dia b/architecture_diagrams/mscontrol/call-add-participant.dia new file mode 100644 index 0000000000..48c8dc49b8 Binary files /dev/null and b/architecture_diagrams/mscontrol/call-add-participant.dia differ diff --git a/architecture_diagrams/mscontrol/call-mscontrol-stopping-sequence.dia b/architecture_diagrams/mscontrol/call-mscontrol-stopping-sequence.dia new file mode 100644 index 0000000000..87c4dc3bd7 Binary files /dev/null and b/architecture_diagrams/mscontrol/call-mscontrol-stopping-sequence.dia differ diff --git a/architecture_diagrams/mscontrol/call-mscontrol.dia b/architecture_diagrams/mscontrol/call-mscontrol.dia new file mode 100644 index 0000000000..5c8cebbfce Binary files /dev/null and b/architecture_diagrams/mscontrol/call-mscontrol.dia differ diff --git a/architecture_diagrams/mscontrol/call-sequence-overview.dia b/architecture_diagrams/mscontrol/call-sequence-overview.dia new file mode 100644 index 0000000000..db3f821207 Binary files /dev/null and b/architecture_diagrams/mscontrol/call-sequence-overview.dia differ diff --git a/architecture_diagrams/mscontrol/call-workflow-suggestion.dia b/architecture_diagrams/mscontrol/call-workflow-suggestion.dia new file mode 100644 index 0000000000..cc8ee28700 Binary files /dev/null and b/architecture_diagrams/mscontrol/call-workflow-suggestion.dia differ diff --git a/architecture_diagrams/mscontrol/call.dia b/architecture_diagrams/mscontrol/call.dia new file mode 100644 index 0000000000..8f70f3d212 Binary files /dev/null and b/architecture_diagrams/mscontrol/call.dia differ diff --git a/architecture_diagrams/mscontrol/conference-add-participant.dia b/architecture_diagrams/mscontrol/conference-add-participant.dia new file mode 100644 index 0000000000..48ac612538 Binary files /dev/null and b/architecture_diagrams/mscontrol/conference-add-participant.dia differ diff --git a/architecture_diagrams/mscontrol/conference-mscontrol.dia b/architecture_diagrams/mscontrol/conference-mscontrol.dia new file mode 100644 index 0000000000..9d0af20dc3 Binary files /dev/null and b/architecture_diagrams/mscontrol/conference-mscontrol.dia differ diff --git a/architecture_diagrams/mscontrol/conference-termination.dia b/architecture_diagrams/mscontrol/conference-termination.dia new file mode 100644 index 0000000000..6b3682c33d Binary files /dev/null and b/architecture_diagrams/mscontrol/conference-termination.dia differ diff --git a/architecture_diagrams/mscontrol/conference.dia b/architecture_diagrams/mscontrol/conference.dia new file mode 100644 index 0000000000..5b2c2af58e Binary files /dev/null and b/architecture_diagrams/mscontrol/conference.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/bridge-mscontrol-jsr309.dia b/architecture_diagrams/mscontrol/jsr309/bridge-mscontrol-jsr309.dia new file mode 100644 index 0000000000..a4476325bc Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/bridge-mscontrol-jsr309.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/bridge-resources-overview.dia b/architecture_diagrams/mscontrol/jsr309/bridge-resources-overview.dia new file mode 100644 index 0000000000..f72e203c7c Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/bridge-resources-overview.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/call-mscontrol-jsr309.dia b/architecture_diagrams/mscontrol/jsr309/call-mscontrol-jsr309.dia new file mode 100644 index 0000000000..7824df0978 Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/call-mscontrol-jsr309.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/call-resources-overview.dia b/architecture_diagrams/mscontrol/jsr309/call-resources-overview.dia new file mode 100644 index 0000000000..58cb728213 Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/call-resources-overview.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/conference-mscontrol-jsr309.dia b/architecture_diagrams/mscontrol/jsr309/conference-mscontrol-jsr309.dia new file mode 100644 index 0000000000..5cf6f66cb5 Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/conference-mscontrol-jsr309.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/conference-resources-overview.dia b/architecture_diagrams/mscontrol/jsr309/conference-resources-overview.dia new file mode 100644 index 0000000000..f18d3ec361 Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/conference-resources-overview.dia differ diff --git a/architecture_diagrams/mscontrol/jsr309/conference-workflow-join-participant-jsr309.dia b/architecture_diagrams/mscontrol/jsr309/conference-workflow-join-participant-jsr309.dia new file mode 100644 index 0000000000..38be00834e Binary files /dev/null and b/architecture_diagrams/mscontrol/jsr309/conference-workflow-join-participant-jsr309.dia differ diff --git a/architecture_diagrams/mscontrol/mscontrol-classes.dia b/architecture_diagrams/mscontrol/mscontrol-classes.dia new file mode 100644 index 0000000000..e14e3a500f Binary files /dev/null and b/architecture_diagrams/mscontrol/mscontrol-classes.dia differ diff --git a/architecture_diagrams/mscontrol/mscontrol-packages.dia b/architecture_diagrams/mscontrol/mscontrol-packages.dia new file mode 100644 index 0000000000..7964542458 Binary files /dev/null and b/architecture_diagrams/mscontrol/mscontrol-packages.dia differ diff --git a/architecture_diagrams/mscontrol/sub-voice-interpreter.dia b/architecture_diagrams/mscontrol/sub-voice-interpreter.dia new file mode 100644 index 0000000000..912eea57ef Binary files /dev/null and b/architecture_diagrams/mscontrol/sub-voice-interpreter.dia differ diff --git a/architecture_diagrams/mscontrol/voice-interpreter.dia b/architecture_diagrams/mscontrol/voice-interpreter.dia new file mode 100644 index 0000000000..7f67ee2967 Binary files /dev/null and b/architecture_diagrams/mscontrol/voice-interpreter.dia differ diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..dcb610ff59 --- /dev/null +++ b/build.sh @@ -0,0 +1,65 @@ +#!/bin/bash +export MAVEN_OPTS="-Xms1024m -Xmx2048m -XX:MaxPermSize=1024m" +export ANT_HOME=/opt/ant/apache-ant-1.8.3 + +rm Restcomm*.zip -rf +rm dependencies -rf + +echo "MAJOR VERSION NUMBER: $MAJOR_VERSION_NUMBER" +echo "RESTCOMM BRANCH: $RESTCOMM_BRANCH" +echo "RUN TESTSUITE: $RUN_TESTSUITE" + +export WORKSPACE=$TRAVIS_BUILD_DIR +export BUILD_NUMBER=$TRAVIS_BUILD_NUMBER + +export DEPENDENCIES_HOME=$WORKSPACE/dependencies +mkdir $DEPENDENCIES_HOME +export RESTCOMM_HOME=$WORKSPACE +export RELEASE=$RESTCOMM_HOME/release +cd $RESTCOMM_HOME/restcomm +git checkout -b restcomm-release-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER +git rev-parse HEAD > git-info-restcomm.txt +echo $MAJOR_VERSION_NUMBER.$BUILD_NUMBER >> mss-version.txt + +mvn versions:set -DnewVersion=$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -P docs +git commit -a -m "New release candidate $MAJOR_VERSION_NUMBER.$BUILD_NUMBER" + +cd $RELEASE +FILE=$RESTCOMM_HOME/restcomm/configuration/mss-sip-stack.properties +sed -e "s|MAJOR_VERSION_NUMBER.BUILD_NUMBER|$MAJOR_VERSION_NUMBER.$BUILD_NUMBER|g" $FILE > $FILE.bak +mv $FILE.bak $FILE +ant release -f $RESTCOMM_HOME/release/build.xml -Drestcomm.release.version=$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Drestcomm.branch.name=restcomm-release-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Dcheckout.restcomm.dir=$RESTCOMM_HOME -Dworkspace.restcomm.dir=$RESTCOMM_HOME/restcomm -Dcheckout.dir=$DEPENDENCIES_HOME +mv $RELEASE/Restcomm-*.zip $WORKSPACE +ls -la $WORKSPACE/Restcomm-JBoss-AS7-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER.zip + +echo "About to upload to Bintray" +curl -T $WORKSPACE/Restcomm-JBoss-AS7-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER.zip -ugvagenas:$BINTRAY_API_KEY -H "X-Bintray-Package:binaries" -H "X-Bintray-Version:8.2.0" https://api.bintray.com/content/gvagenas/Restcomm-Connect/bin/ + + +cd $RESTCOMM_HOME/restcomm +#commenting the deploy command as it eats up storage on artifactory +#mvn deploy -Dmaven.test.skip=true +#mvn -Dgpg.passphrase="$GPG_PASSPHRASE" -f pom.xml clean install deploy -Pattach-sources,generate-javadoc,release-sign-artifacts,cloudbees-oss-release -s /private/mobicents/settings.xml -Dmaven.test.skip=true + +#if [ "$RUN_TESTSUITE" = "true" ] +#then +#mvn -fn surefire-report:report -Dmaven.test.failure.ignore=true +#else +#echo "Will not run test suite because variable is $RUN_TESTSUITE" +#fi + +echo "$MAJOR_VERSION_NUMBER.$BUILD_NUMBER" > $WORKSPACE/restcomm-version.txt +ls -la $WORKSPACE/*.zip +md5sum $WORKSPACE/*.zip +sha1sum $WORKSPACE/*.zip + +git commit -a -m 'New release candidate' +git tag $MAJOR_VERSION_NUMBER.$BUILD_NUMBER +git push origin $MAJOR_VERSION_NUMBER.$BUILD_NUMBER + +cd $RESTCOMM_HOME/restcomm +mvn -Dlicense.includedScopes=compile license:aggregate-add-third-party + +# sonarqube integration +#cd $RESTCOMM_HOME/restcomm +#mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dmaven.test.failure.ignore=true -Dsonar.host.url=https://nemo.sonarqube.org -Dsonar.login=Restcomm diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..1723d3562c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,140 @@ +# IMPORTANT: this file is intended to help you quickly get started with deploying RestComm. +# It is NOT intended for production deployments. + +version: '3.1' + +volumes: +# You can persist the logs, database, recordings, text-to-speech cache and RVD workspace using shared filesystem, so even if you stop and remove +# your container, your work won't be lost. Download the https://github.com/restcomm/Restcomm-Docker/blob/master/restcomm_workspace.zip?raw=true[*restcomm_workspace*] +# that contains the default database, default RVD workspace and the required folders and unzip it to a folder in your filesystem. + restcomm_logs: + recordings: + cache: + hsql_data: + rvd_workspace: + +services: + restcomm: + image: restcomm/restcomm:latest + volumes: + - restcomm_logs:/var/log/restcomm + - recordings:/opt/Restcomm-JBoss-AS7/standalone/deployments/restcomm.war/recordings + - cache:/opt/Restcomm-JBoss-AS7/standalone/deployments/restcomm.war/cache + - hsql_data:/var/restcomm/data + - rvd_workspace:/opt/Restcomm-JBoss-AS7/standalone/deployments/restcomm-rvd + + environment: + ## =============================== IMPORTANT!! While most of the below defaults should be fine, YOU PROBABLY NEED TO CHANGE THIS!! + RCBCONF_STATIC_ADDRESS: 127.0.0.1 # YOUR LOCAL IP ADDRESS GOES HERE. + RMSCONF_EXTERNAL_ADDRESS: 127.0.0.1 # YOUR LOCAL IP ADDRESS GOES HERE. + ## =============================== IMPORTANT ======================================================================================== + + # ENVCONFURL: https://raw.githubusercontent.com/RestComm/Restcomm-Docker/master/env_files/restcomm_env_locally.sh + # REPOUSR: Username for `ENVCONFURL` if Authentication needed. + # REPOPWD: Password for `ENVCONFURL` if Authentication needed. + + EXTCONF_RESTCOMM_LOGS: /var/log/restcomm + EXTCONF_CORE_LOGS_LOCATION: restcomm_core + EXTCONF_RESTCOMM_TRACE_LOG: restcomm_trace + EXTCONF_MEDIASERVER_LOGS_LOCATION: media_server + + #SSL certificate + # Below options set up a self-signed certificate for HTTPS. The generated truststore file will be located at + # `/opt/Mobicents-Restcomm-JBoss-AS7/standalone/configuration/restcomm-combined.jks` + RCADVCONF_SECURESSL: SELF + RCADVCONF_SSL_MODE: allowall + RCADVCONF_TRUSTSTORE_PASSWORD: changeme + RCADVCONF_TRUSTSTORE_ALIAS: restcomm + + #Functional configuration. Make sure these match the published port range in the `ports` section below. + RMSCONF_MEDIA_LOW_PORT: 65000 + RMSCONF_MEDIA_HIGH_PORT: 65050 + + #RestComm Port configuration. Make sure these match the published ports in the `ports` section below. + RCBCONF_SIP_PORT_UDP: 5080 + RCBCONF_SIP_PORT_TCP: 5080 + RCBCONF_SIP_PORT_TLS: 5081 + RCBCONF_SIP_PORT_WS: 5082 + RCBCONF_SIP_PORT_WSS: 5083 + + #Log + RCBCONF_LOG_LEVEL: DEBUG + RCBCONF_AKKA_LOG_LEVEL: INFO + RCBCONF_LOG_LEVEL_COMPONENT_GOVNIST: INFO + RCBCONF_LOG_LEVEL_COMPONENT_SIPSERVLET: INFO + RCBCONF_LOG_LEVEL_COMPONENT_SIPRESTCOMM: INFO + RCBCONF_LOG_LEVEL_COMPONENT_RESTCOMM: INFO + + #SMS + RCBCONF_SMS_PREFIX: '' + + #TTS - Text To Speech + RCBCONF_VOICERSS_KEY: VOICERSS_KEY_HERE #FIXME: You may get a free VoiceRSS API key from http://www.voicerss.org/from + + #RVD_LOCATION + RCADVCONF_RVD_LOCATION: /var/restcomm/rvd/workspace + + #HSQL-persist data + RCADVCONF_HSQL_DIR: /var/restcomm/data # Defines path where HSQL data will be persisted. + + + # Powermedia XMS integration: uncomment below env vars. Also: + # + # RMSCONF_MS_COMPATIBILITY_MODE: xms + # RMSCONF_MS_ADDRESS: 127.0.0.1 # The IP of a working Powermedia XMS server. + # NOTE: In our example, we are assuming Powermedia XMS is installed on the host where Restcomm-Connect is running in a Docker container. As + # such, they can share a docker volume for storing recordings (the `recordings` volume). XMS should be configured to store files to that + # directory. For more complex examples, you'll want to set up NFS shares, etc. + + + # The RestComm docker image supports the same set of environment variables with RestComm, with some prefix, depending on the config file it is in. + # - Variables that are located at "restcomm.conf" need to be prefixed with "RCBCONF_" + # - Variables that are located at "advanced.conf" need to be prefixed with "RCADVCONF_" + # - Variables that are used to configure RMS ("mediaserver.conf") need to be prefixed with "RMSCONF_" + # - Variables that are docker specific only need to be prefixed with "EXTCONF_". + # - Variables that are used to configure Load Balancer need to be prefixed with "LBCONF_". + # - Variables that are set from the RUN command line to overwrite the ones set at the configuration file need to be prefixed with "CLI_". + + # Docker Specific Environment Variables + # ===== RestComm Logs Configuration + # * *EXTCONF_RESTCOMM_LOGS* Base path where all RestComm related logs will be placed. + # * *EXTCONF_RESTCOMM_TRACE_LOG* Set the location were to store network trace logs (pcap files) + # * *EXTCONF_MEDIASERVER_LOGS_LOCATION* Set the location were to store Mediaserver l og + + # ===== Other + # * *EXTCONF_RVD_PORT* Used when port mapping at docker is not the default (e.g: -p 445:443 + + # Related Documentation + # + # RestComm configuration: http://documentation.telestax.com/core/media_server/Media_Server_User_Guide.html#_ctms_configuring_the_media_server. + # config files: + # - restcomm.conf https://raw.githubusercontent.com/RestComm/Restcomm-Connect/master/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf + # - advanced.conf https://raw.githubusercontent.com/RestComm/Restcomm-Connect/master/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf + # RMS configuration http://documentation.telestax.com/core/media_server/Media_Server_User_Guide.html#_ctms_configuring_the_media_server + + ports: +# - "8080:8080" # RestComm Console HTTP Port. Disabled by default, so you get used to HTTPS ; ) + - "8443:8443" # RestComm Console HTTPS Port + - "9990:9990" # RestComm Console Management Port + - "5080:5080/udp" # SIP/UDP + - "5080:5080" # SIP/TCP + - "5081:5081" # SIP/TLS + - "5082:5082" # SIP/WS (Used for WebRTC - SIP Over WebSockets) + - "5083:5083" # SIP/WSS (Used for WebRTC - Secure SIP Over WebSockets) + - "65000-65050:65000-65050/udp" # RTP/UDP + + # To specify additional custom port connectors add `ADDITIONAL_CONNECTOR_1=second-sip-udp:5090`, `ADDITIONAL_CONNECTOR_2=second-sip-tcpp:5090` + # env vars and export port in this section. More info http://documentation.telestax.com/core/sip_servlets/SIP_Servlets_Server_User_Guide.html + +# IMPORTANT! COMMENT OUT BELOW ON OSX / macOS. (you thought "Host" is really your host, didn't you? Well, let me tell you +# about this embedded hypervisor called "xhyve" and how it's not all really "native" the way you took that to mean... : ) ) +# network_mode: "host" + + restart: always + + logging: + driver: "json-file" + # Uncomment below to enable logs rotation. (Rotate using 3 files 20m each file) + # options: + # max-size: "20m" + # max-file: "3" \ No newline at end of file diff --git a/liveCallModification/LiveCallModificationAPI_June1_2015.pdf b/liveCallModification/LiveCallModificationAPI_June1_2015.pdf new file mode 100644 index 0000000000..466caef5d8 Binary files /dev/null and b/liveCallModification/LiveCallModificationAPI_June1_2015.pdf differ diff --git a/liveCallModification/hold.sh b/liveCallModification/hold.sh new file mode 100755 index 0000000000..a06f4de1d1 --- /dev/null +++ b/liveCallModification/hold.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +############################################################ +# Alice calls Bob. Given Alice call_sid, use this script to +# move both calls to a conference room with music and muted +# that means to hold the call. +############################################################ + +#Provide Restcomm ip address +restcomm_ip= +#Provide Username sid +userSid= +#Provide Auth Token +authToken= + +#Call SID of the call to move. Use the call SID of the initial Call +sid=$1 + +echo "Moving call $1 to Conference" + +curl -X POST http://$userSid:$authToken@$restcomm_ip:8080/restcomm/2012-04-24/Accounts/$userSid/Calls.json/$1 -d "Url=http://$restcomm_ip:8080//restcomm/demos/dial/conference/dial-conference.xml" -d "MoveConnectedCallLeg=true" diff --git a/liveCallModification/unhold.sh b/liveCallModification/unhold.sh new file mode 100755 index 0000000000..955a27ce17 --- /dev/null +++ b/liveCallModification/unhold.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +############################################################ +# Use this script to unhold a call previously set on hold +############################################################ + +#Provide Restcomm ip address +restcomm_ip= +#Provide Username sid +userSid= +#Provide Auth Token +authToken= + +#Call SID of the call to move. Use the call SID of the initial Call +sid=$1 + +curl -X POST http://$userSid:$authToken@$restcomm_ip:8080/restcomm/2012-04-24/Accounts/$userSid/Calls.json/$1 -d "Url=http://$restcomm_ip:8080/restcomm/demos/dial/conference/dial-conference-moderator.xml " diff --git a/release/build-restcomm-local.sh b/release/build-restcomm-local.sh new file mode 100755 index 0000000000..30535782f7 --- /dev/null +++ b/release/build-restcomm-local.sh @@ -0,0 +1,58 @@ +#!/bin/bash +export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m" +export ANT_HOME=/opt/ant/apache-ant-1.8.3 +export WORKSPACE=/tmp/workspace +mkdir $WORKSPACE +cp -ar ../* $WORKSPACE + +CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD` +export MAJOR_VERSION_NUMBER=8.0.0 +export RESTCOMM_BRANCH=$CURRENT_BRANCH +export RUN_TESTSUITE=false +export BUILD_NUMBER=$RESTCOMM_BRANCH-local + +rm Mobicents-Restcomm*.zip +rm dependencies -rf + +echo "MAJOR VERSION NUMBER: $MAJOR_VERSION_NUMBER" +echo "RESTCOMM BRANCH: $RESTCOMM_BRANCH" +echo "RUN TESTSUITE: $RUN_TESTSUITE" + +export DEPENDENCIES_HOME=$WORKSPACE/dependencies +mkdir $DEPENDENCIES_HOME +export RESTCOMM_HOME=$WORKSPACE/Restcomm-Connect +mkdir $RESTCOMM_HOME/restcomm +export RELEASE=$RESTCOMM_HOME/release +cd $RESTCOMM_HOME/restcomm +# git checkout -b restcomm-release-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER +# git rev-parse HEAD > git-info-restcomm.txt +echo $MAJOR_VERSION_NUMBER.$BUILD_NUMBER >> mss-version.txt + +mvn versions:set -DnewVersion=$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -P docs +git commit -a -m "New release candidate $MAJOR_VERSION_NUMBER.$BUILD_NUMBER" + +cd $RELEASE +FILE=$RESTCOMM_HOME/restcomm/configuration/mss-sip-stack.properties +sed -e "s|MAJOR_VERSION_NUMBER.BUILD_NUMBER|$MAJOR_VERSION_NUMBER.$BUILD_NUMBER|g" $FILE > $FILE.bak +mv $FILE.bak $FILE +ant release -f $RESTCOMM_HOME/release/build.xml -Drestcomm.release.version=$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Drestcomm.branch.name=restcomm-release-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Dcheckout.restcomm.dir=$RESTCOMM_HOME -Dworkspace.restcomm.dir=$RESTCOMM_HOME/restcomm -Dcheckout.dir=$DEPENDENCIES_HOME +mv $RELEASE/Restcomm-*.zip $WORKSPACE + +cd $RESTCOMM_HOME/restcomm +#commenting the deploy command as it eats up storage on artifactory +#mvn deploy -Dmaven.test.skip=true + +if [ "$RUN_TESTSUITE" = "true" ] +then +mvn -fn test -Dmaven.test.failure.ignore=true +else +echo "Will not run test suite because variable is $RUN_TESTSUITE" +fi + +echo "$MAJOR_VERSION_NUMBER.$BUILD_NUMBER" > $WORKSPACE/restcomm-version.txt +ls -la $WORKSPACE/*.zip +md5sum $WORKSPACE/*.zip +sha1sum $WORKSPACE/*.zip + +# git tag $MAJOR_VERSION_NUMBER.$BUILD_NUMBER +# git push origin $MAJOR_VERSION_NUMBER.$BUILD_NUMBER diff --git a/release/build.xml b/release/build.xml index 2bdad70fdb..012480b413 100755 --- a/release/build.xml +++ b/release/build.xml @@ -1,399 +1,331 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading HSQLDB Driver for Tomcat version: ${mobicents-sipservlets.version} - - - - - - - - - Downloading mobicents SipServlets Tomcat version: ${mobicents-sipservlets-as7.version} - - - - - - - - - - Downloading mobicents SipServlets JBoss AS7 version: ${mobicents-sipservlets-as7.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading mobicents Media version: ${mobicents-media.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading mobicents Diameter version: ${mobicents-diameter.version} - - - - - - - - - - - - - Building mobicents Restcomm - Restcomm workspace dir: "${workspace.mobicents-restcomm.dir}" - - - - - - - - - - - - - Copy restcomm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Will retrieve RVD from ${restcomm-rvd.download.url} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading Restcomm SipServlets JBoss AS7 version: ${restcomm-sipservlets-as7.version} + + + + + + + + + + + + + + + + + + + Downloading Restcomm Media version: ${restcomm-media.version}.${restcomm-media.build} + + + + + + + + + + + Downloading Restcomm Olympus version: ${olympus.version} + + + + + + + + + + + Downloading latest version of Visual Designer + + + + + + + + + + + + + + + + + + + + + + + Building Restcomm + Restcomm workspace dir: "${workspace.restcomm.dir}" + + + + + + + + + + + Copy restcomm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - +--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/release/build.xml_orig b/release/build.xml_orig new file mode 100755 index 0000000000..3297a9fce2 --- /dev/null +++ b/release/build.xml_orig @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading mobicents SipServlets Tomcat version: ${mobicents-sipservlets-as7.version} + + + + + + + + + + Downloading mobicents SipServlets JBoss AS7 version: ${mobicents-sipservlets-as7.version} + + + + + + + + + + + + + + + + + + + + + + + + Downloading mobicents Media version: ${mobicents-media.version} + + + + + + + + + + + Downloading mobicents Olympus version: ${olympus.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading mobicents Diameter version: ${mobicents-diameter.version} + + + + + + + + + + + + + Building mobicents Restcomm + Restcomm workspace dir: "${workspace.mobicents-restcomm.dir}" + + + + + + + + + + + + + Copy restcomm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + export APPSERVER_PLATFORM='TELESTAX' export DLG_PROPERTY_FILE=$CATALINA_HOME/conf/dlgc_JSR309.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + export APPSERVER_PLATFORM='TELESTAX' export DLG_PROPERTY_FILE=${JBOSS_HOME}/standalone/configuration/dlgc_JSR309.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/release/build.xml~ b/release/build.xml~ deleted file mode 100755 index 6475fc7d8e..0000000000 --- a/release/build.xml~ +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading HSQLDB Driver for Tomcat version: ${mobicents-sipservlets.version} - - - - - - - - - Downloading mobicents SipServlets Tomcat version: ${mobicents-sipservlets-as7.version} - - - - - - - - - - Downloading mobicents SipServlets JBoss AS7 version: ${mobicents-sipservlets-as7.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading mobicents Media version: ${mobicents-media.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading mobicents Diameter version: ${mobicents-diameter.version} - - - - - - - - - - - - - Building mobicents Restcomm - Restcomm workspace dir: "${workspace.mobicents-restcomm.dir}" - - - - - - - - - - - - - Copy restcomm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/release/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh b/release/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh deleted file mode 100755 index 254a40367b..0000000000 --- a/release/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh +++ /dev/null @@ -1,20 +0,0 @@ -#! /bin/bash -## -## Description: Executes all RestComm configuration scripts for a given version. -## Author : Henrique Rosa -## -BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) - -# load configuration values -#source $BASEDIR/restcomm.conf - -echo '' -echo 'RestComm automatic configuration started:' -for f in $BASEDIR/autoconfig.d/*.sh; do - echo "Executing configuration file $f..." - source $f - echo "Finished executing configuration file $f!" - echo '' -done -echo 'RestComm automatic configuration finished!' -echo '' \ No newline at end of file diff --git a/release/config-scripts/as7-config-scripts/restcomm/restcomm.conf b/release/config-scripts/as7-config-scripts/restcomm/restcomm.conf deleted file mode 100755 index 6d678d8f02..0000000000 --- a/release/config-scripts/as7-config-scripts/restcomm/restcomm.conf +++ /dev/null @@ -1,44 +0,0 @@ -#! /bin/bash - -## -## Description: List of variables used to configure RestComm -## Author : Henrique Rosa -## - -# Network configuration -NET_INTERFACE= -PRIVATE_IP= -SUBNET_MASK= -NETWORK= -BROADCAST_ADDRESS= - -# Address for outbound calls -OUTBOUND_IP='' - -# VoIP Innovations variable declarations -VI_LOGIN='' -VI_PASSWORD='' -VI_ENDPOINT='' - -# Interfax variable declarations. -INTERFAX_USER='' -INTERFAX_PASSWORD='' - -# ISpeech variable declarations. -ISPEECH_KEY='' - -# VoiceRSS variable declarations -VOICERSS_KEY='' - -# Acapela variable declarations. -ACAPELA_APPLICATION='' -ACAPELA_LOGIN='' -ACAPELA_PASSWORD='' - -# Proxy variable declarations -ACTIVE_PROXY='' -TP_LOGIN='' -TP_PASSWORD='' -PROXY_IP='' -INSTANCE_ID='' -PROXY_PRIVATE_IP='10.179.184.34' diff --git a/release/config-scripts/as7-config-scripts/restcomm/smpp.conf b/release/config-scripts/as7-config-scripts/restcomm/smpp.conf new file mode 100644 index 0000000000..2ef25fedc2 --- /dev/null +++ b/release/config-scripts/as7-config-scripts/restcomm/smpp.conf @@ -0,0 +1,8 @@ +# Connection details for SMPP Restcomm integration +SMPP_ACTIVATE='false' #default SMPP activate is always false. Set to true to activate SMPP +SMPP_SYSTEM_ID='' +SMPP_PASSWORD='' +SMPP_SYSTEM_TYPE='' #This is required when working with Nexmo for inboudn SMS +SMPP_PEER_IP='' #use IP or DNS name of peer SMPP server +SMPP_PEER_PORT='' + diff --git a/release/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh b/release/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh deleted file mode 100755 index cccdc148be..0000000000 --- a/release/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh +++ /dev/null @@ -1,167 +0,0 @@ -#! /bin/bash -## -## Description: Starts RestComm with auto-configuration. -## -## Parameters : 1. Bind Address (default: 127.0.0.1) -## 2. Run Mode [standalone|standalone-lb|domain|domain-lb] (default:standalone) -## -## Author : Henrique Rosa -## - -## -## FUNCTIONS -## -startRestcomm() { - run_mode="$1" - bind_address="$2" - - # Check if RestComm is already running - if screen -list | grep -q 'restcomm'; then - echo 'TelScale RestComm is already running on screen session "restcomm"!' - exit 1; - fi - - case $run_mode in - 'standalone'*) - # start restcomm on standalone mode - chmod +x $RESTCOMM_HOME/bin/standalone.sh - screen -dmS 'restcomm' $RESTCOMM_HOME/bin/standalone.sh -b $bind_address - echo 'TelScale RestComm started running on standalone mode. Screen session: restcomm.' - echo "Using IP Address: $BIND_ADDRESS" - ;; - 'domain'*) - # start restcomm on standalone mode - chmod +x $RESTCOMM_HOME/bin/domain.sh - screen -dmS 'restcomm' $RESTCOMM_HOME/bin/domain.sh -b $bind_address - echo 'TelScale RestComm started running on domain mode. Screen session: restcomm.' - echo "Using IP Address: $BIND_ADDRESS" - ;; - *) - # start restcomm on standalone mode - chmod +x $RESTCOMM_HOME/bin/standalone.sh - screen -dmS 'restcomm' $RESTCOMM_HOME/bin/standalone.sh -b $bind_address - echo 'TelScale RestComm started running on standalone mode. Screen session: restcomm.' - echo "Using IP Address: $BIND_ADDRESS" - ;; - esac - - - if [[ "$run_mode" == *"-lb" ]]; then - echo 'Starting SIP Load Balancer...' - if screen -ls | grep -q 'balancer'; then - echo 'SIP Load Balancer is already running on screen session "balancer"!' - else - screen -dmS 'balancer' java -DlogConfigFile=$LB_HOME/lb-log4j.xml \ - -jar $LB_HOME/sip-balancer-jar-with-dependencies.jar \ - -mobicents-balancer-config=$LB_HOME/lb-configuration.properties - echo 'SIP Load Balancer started running on screen session "balancer"!' - echo "Using IP Address: $BIND_ADDRESS" - fi - fi -} - -startMediaServer() { - echo "Starting Mobicents Media Server..." - echo "Media Server will bind to the IP Address: $BIND_ADDRESS" - if screen -ls | grep -q 'mms'; then - echo '...Mobicents Media Server is already running on screen session "mms"!' - else - chmod +x $MMS_HOME/bin/run.sh - screen -dmS 'mms' $MMS_HOME/bin/run.sh - echo '...Mobicents Media Server started running on screen "mms"!' -fi -} - -## -## MAIN -## -# GNU screen needs to be installed -if [ -z "$(command -v screen)" ]; then - echo "ERROR: GNU Screen is not installed! Install it and try again." - echo "Centos/RHEL: yum install screen" - echo "Debian/Ubuntu: apt-get install screen" - exit 1 -fi - -# ipcalc needs to be installed -if [ -z "$(command -v ipcalc)" ]; then - echo "ERROR: ipcalc is not installed! Install it and try again." - echo "Centos/RHEL: yum install ipcalc" - echo "Debian/Ubuntu: apt-get install ipcalc" - exit 1 -fi - -# set environment variables for execution -BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) -RESTCOMM_HOME=$(cd $BASEDIR/../../ && pwd) -MMS_HOME=$RESTCOMM_HOME/telscale-media/telscale-media-server -LB_HOME=$RESTCOMM_HOME/tools/sip-balancer - -echo BASEDIR: $BASEDIR -echo RESTCOMM_HOME: $RESTCOMM_HOME -source $BASEDIR/restcomm.conf - -# input parameters and default values -RUN_MODE='standalone' -#NET_INTERFACE='' -STATIC_ADDRESS='' -BIND_ADDRESS='' - -while getopts "s:r:i:" optname -do - case "$optname" in - "s") - STATIC_ADDRESS="$OPTARG" - ;; - "r") - RUN_MODE="$OPTARG" - ;; - "i") - NET_INTERFACE="$OPTARG" - ;; - ":") - echo "No argument value for option $OPTARG" - exit 1 - ;; - "?") - echo "Unknown option $OPTARG" - exit 1 - ;; - *) - echo 'Unknown error while processing options' - exit 1 - ;; - esac -done - -# validate network interface and extract network properties -if [[ -z "$NET_INTERFACE" ]]; then -NET_INTERFACE='eth0' -echo "Looking for the appropriate interface" - NET_INTERFACES=$(ifconfig | expand | cut -c1-8 | sort | uniq -u | awk -F: '{print $1;}') - if [[ -z $(echo $NET_INTERFACES | sed -n "/$NET_INTERFACE/p") ]]; then - echo "The network interface $NET_INTERFACE is not available or does not exist." - echo "The list of available interfaces is: $NET_INTERFACES" - exit 1 - fi -fi - -# load network properties for chosen interface -if [[ -z "$PRIVATE_IP" || -z "$SUBNET_MASK" || -z "$NETWORK" || -z "$BROADCAST_ADDRESS" ]]; then -echo "Looking for the IP Address, subnet, network and broadcast_address" - source $BASEDIR/utils/read-network-props.sh "$NET_INTERFACE" -fi -BIND_ADDRESS="$PRIVATE_IP" - - -if [[ -z "$STATIC_ADDRESS" ]]; then - STATIC_ADDRESS=$BIND_ADDRESS -fi - -# configure restcomm installation -source $BASEDIR/autoconfigure.sh - -# start restcomm in selected run mode -startRestcomm "$RUN_MODE" "$BIND_ADDRESS" -startMediaServer -exit 0 diff --git a/release/mms-server-beans.xml b/release/mms-server-beans.xml deleted file mode 100644 index d53f5ea115..0000000000 --- a/release/mms-server-beans.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - 127.0.0.1 - 127.0.0.1 - 127.0.0.1 - 255.255.255.255 - false - 0 - - - - - - - - - - - - 50 - - - - - - - - org.mobicents.media.server.impl.dsp.audio.l16.Encoder - org.mobicents.media.server.impl.dsp.audio.l16.Decoder - org.mobicents.media.server.impl.dsp.audio.g711.alaw.Encoder - org.mobicents.media.server.impl.dsp.audio.g711.alaw.Decoder - org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Encoder - org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Decoder - - - - - - - - - - - - 5 - 5 - 5 - 0 - 0 - 0 - 10 - 10 - 0 - - - - - - 2427 - - - mgcp-conf.xml - 25 - - - - - - - - - 1 - - - - - - - - mobicents/ivr/ - org.mobicents.media.core.endpoints.impl.IvrEndpoint - 50 - - - - mobicents/cnf/ - org.mobicents.media.core.endpoints.impl.ConferenceEndpoint - 50 - - - - mobicents/bridge/ - org.mobicents.media.core.endpoints.impl.BridgeEndpoint - 50 - - - - mobicents/relay/ - org.mobicents.media.core.endpoints.impl.PacketRelayEndpoint - 50 - - - - - - diff --git a/restcomm/configuration/README b/restcomm/configuration/README new file mode 100644 index 0000000000..8ea49bcc07 --- /dev/null +++ b/restcomm/configuration/README @@ -0,0 +1,2 @@ +For Restcomm documentation please visit +http://docs.telestax.com/restcomm-pages/ diff --git a/restcomm/configuration/RvdExternalServicesDemo.war b/restcomm/configuration/RvdExternalServicesDemo.war new file mode 100644 index 0000000000..31f5987e73 Binary files /dev/null and b/restcomm/configuration/RvdExternalServicesDemo.war differ diff --git a/release/RvdExternalServicesDemo.war b/restcomm/configuration/RvdExternalServicesDemo_old_Charles.war similarity index 100% rename from release/RvdExternalServicesDemo.war rename to restcomm/configuration/RvdExternalServicesDemo_old_Charles.war diff --git a/restcomm/configuration/Telestax-EULA.pdf b/restcomm/configuration/Telestax-EULA.pdf new file mode 100644 index 0000000000..4bdecb3af7 Binary files /dev/null and b/restcomm/configuration/Telestax-EULA.pdf differ diff --git a/restcomm/configuration/as7-standalone.conf b/restcomm/configuration/as7-standalone.conf new file mode 100644 index 0000000000..531fa349f9 --- /dev/null +++ b/restcomm/configuration/as7-standalone.conf @@ -0,0 +1,70 @@ +## -*- shell-script -*- ###################################################### +## ## +## JBoss Bootstrap Script Configuration ## +## ## +############################################################################## + +# +# This file is optional; it may be removed if not needed. +# + +# +# Specify the maximum file descriptor limit, use "max" or "maximum" to use +# the default, as queried by the system. +# +# Defaults to "maximum" +# +#MAX_FD="maximum" + +# +# Specify the profiler configuration file to load. +# +# Default is to not load profiler configuration file. +# +#PROFILER="" + +# +# Specify the location of the Java home directory. If set then $JAVA will +# be defined to $JAVA_HOME/bin/java, else $JAVA will be "java". +# +#JAVA_HOME="/opt/java/jdk" + +# +# Specify the exact Java VM executable to use. +# +#JAVA="" + +if [ "x$JBOSS_MODULES_SYSTEM_PKGS" = "x" ]; then + JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman" +fi + +# Uncomment the following line to prevent manipulation of JVM options +# by shell scripts. +# +#PRESERVE_JAVA_OPTS=true + +# +# Specify options to pass to the Java VM. +# +if [ "x$JAVA_OPTS" = "x" ]; then + JAVA_OPTS="" + JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS -Djava.awt.headless=true" +else + echo "JAVA_OPTS already set in environment; overriding default settings with values: $JAVA_OPTS" +fi + +#https://telestax.atlassian.net/browse/MSS-95 setup MSS conf file and default license dir +JAVA_OPTS="$JAVA_OPTS -Djboss.server.default.config=standalone-sip.xml" + + +# Sample JPDA settings for remote socket debugging +#JAVA_OPTS="$JAVA_OPTS -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n" + +# Sample JPDA settings for shared memory debugging +#JAVA_OPTS="$JAVA_OPTS -Xrunjdwp:transport=dt_shmem,server=y,suspend=n,address=jboss" + +# Uncomment to not use JBoss Modules lockless mode +#JAVA_OPTS="$JAVA_OPTS -Djboss.modules.lockless=false" + +# Uncomment to gather JBoss Modules metrics +#JAVA_OPTS="$JAVA_OPTS -Djboss.modules.metrics=true" diff --git a/release/catalina.sh b/restcomm/configuration/catalina.sh similarity index 100% rename from release/catalina.sh rename to restcomm/configuration/catalina.sh diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf new file mode 100644 index 0000000000..3e3743c02e --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf @@ -0,0 +1,150 @@ +#! /bin/bash + +## +## Description: List of variables used to configure RestComm +## Author : Lefteris Banos +## + +#Manual Configuration. +#If set no automatic configuration will done. Everything needs to be set manually. +MANUAL_SETUP='FALSE' #Used to configure RestComm manually and not take under consideration restcomm.conf & advanced.conf files. + +#Secure SSL configuration. +#Allowed values FALSE, SELF, AUTH. +#If SELF set self-signed certificate will be created. +#If AUTH, Authorized certificate will be used.Need to place the certificate at "$RESTCOMM_HOME/standalone/configuration/" +#To Disable use 'FALSE' +SECURESSL=FALSE +TRUSTSTORE_FILE='restcomm-crt.jks' #File should be located at $RESTCOMM_HOME/standalone/configuration folder. Provide just the name of the trustore file. +TRUSTSTORE_PASSWORD='changeme' #Password for the trustore file +TRUSTSTORE_ALIAS='restcomm' #The certificate alias + +#HTTPS Settings +DISABLE_HTTP='false' #Control HTTP connector behavior. Values, TRUE=HTTP connector will be disable, FALSE=HTTP Connector will be active, REDIRECT= http -> https redirection will be enabled (For CLI RestAPI requests when redirect is active https needs to be used). +#Control whether or not Restcomm will accept self-signed certificates. +SSL_MODE='strict' #Values allowall=allow self-signed certificates, strict=don't allow self signed certificates. If SECURESSL=SELF set to "allowall" automatically. + +#JAVA Options +#JVM Options used to RUN RC and RMS. +#RestComm JAVA_OPTS +#RC_JAVA_OPTS='-Xms1024m -Xmx4096m -Xmn512m -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycle=100 -XX:CMSIncrementalDutyCycleMin=100 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:MaxPermSize=512m -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dorg.jboss.server.bootstrap.maxThreads=1 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../../restcomm_dumpfile-$(date +%b_%d_%Y_%H_%M_%S).bin' +RC_JAVA_OPTS="-Xms1048m -Xmx4096m -XX:MaxPermSize=512m -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1RSetUpdatingPauseTimePercent=10 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=4m -XX:G1HeapWastePercent=5 -XX:InitiatingHeapOccupancyPercent=85 -XX:+UnlockExperimentalVMOptions -XX:G1MixedGCLiveThresholdPercent=85 -XX:+AlwaysPreTouch -XX:+UseCompressedOops -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dorg.jboss.server.bootstrap.maxThreads=1 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../../restcomm_dumpfile-$(date +%b_%d_%Y_%H_%M_%S).bin" +#Additional Connectors +#Add extra connectors if needed. Need to use the following rule: +#ADDITIONAL_CONNECTOR_X=CONNECTOR_NAME:PORT +#Available names:sip-tcp,sip-tcp,sip-tls,sip-ws,sip-wss +#More Info Here: http://documentation.telestax.com/core/sip_servlets/SIP_Servlets_Server_User_Guide.html +#Example: +#ADDITIONAL_CONNECTOR_1=second-sip-udp:5090 +#ADDITIONAL_CONNECTOR_2=second-sip-tcp:5090 + +#MYSQL support. +#Default: false. If not configured HSQL will be used. +ENABLE_MYSQL='false' +MYSQL_USER='' +MYSQL_PASSWORD='' +MYSQL_HOST='' +MYSQL_SCHEMA='' +MYSQL_SNDHOST='' #Used for DB redundancy. If set RestComm (Jboss) will point to it if principal DB fails. + +#Amazon S3 Bucket. +#Used to store Recordings. +#Default: false. If not configured internal recordings directory will be used. +ACTIVATE_S3_BUCKET='FALSE' +S3_BUCKET_NAME='' +S3_ACCESS_KEY='' +S3_SECURITY_KEY='' +S3_FOLDER_NAME='' +S3_BUCKET_REGION='' #If not set, "us-east-1" will be used. + +#SMTP Configuration +#Used for system email notifications (When system errors occur). +#As well used for Restcomm email service (Email Verb). +SMTP_USER='' +SMTP_PASSWORD='' +SMTP_HOST='' +SMTP_PORT='' #If not set default Port will be used. Port 25. + +# Configure Load Balancer +ACTIVATE_LB='FALSE' #Set to TRUE to activate and make Restcomm register with LB, the default is FALSE, +LB_PUBLIC_IP='' #The "external" IP of the Telestax LB. Is used for the incoming traffic. +LB_INTERNAL_IP='' #The "internal" IP of the LB. Is used for RC to connect to the LB. If not set LB_PUBLIC_IP will be used. +#Ports that used for interchange between RestComm and Load Balancer +#LB INTERNAL PORTS !!IMPORTANT!!: need to be set same values as LB is configured for the corresponding transport internal Ports. +LB_INTERNAL_PORT_UDP='5080' #LB internal port used from RC for UDP traffic. Default is 5080 +LB_INTERNAL_PORT_TCP='5080' #LB internal port used from RC for TCP traffic. Default is 5080 +LB_INTERNAL_PORT_TLS='5081' #LB internal port used from RC for TLS traffic. Default is 5081 +LB_INTERNAL_PORT_WS='5082' #LB internal port used from RC for WS traffic. Default is 5082 +LB_INTERNAL_PORT_WSS='5083' #LB internal port used from RC for WSS traffic. Default is 5083 +LB_RMI_PORT='2000' #The port used from RMI connection between RC and LB. Default is 2000. +#LB External Ports !!IMPORTANT!!: Need to be set same values as LB is configured for the corresponding transport external Ports. +LB_EXTERNAL_PORT_UDP='5060' #LB external port of LB for UDP traffic. Default is 5060. +LB_EXTERNAL_PORT_TCP='5060' #LB external port of LB for UDP traffic. Default is 5060. +LB_EXTERNAL_PORT_TLS='5061' #LB external port of LB for TLS traffic. Default is 5061. +LB_EXTERNAL_PORT_WS='5062' #LB external port of LB for WS traffic. Default is 5062. +LB_EXTERNAL_PORT_WSS='5063' #LB external port of LB for WSS traffic. Default is 5063. (Port used for Olympus) + +#Load Balancer external HOSTNAME/IP. Must be set if RC under LB. +#Used to configure DID provider.This way PSTN calls going through LB. +#DID_URIPORT will be used for the DID provider PORT configuration. +LBHOST='' #Obligatory to set if Load Balancer is used for PSTN (DID provider configuration). + +#RVD configuration +#RVD workspace path. (If not set default will be used). +#Default: leave empty. +RVD_LOCATION='' +RVD_UNDEPLOY='false' +RVD_URL='' # override if RVD is not under the same domain with restcomm. Use a base url like http://myrvd.restcomm.com . No path included. This affects restcomm.xml/ +RVD_VIDEO_SUPPORT='false' # Toggle RVD Video RCML generation and UI +RVD_MAX_MEDIA_FILE_SIZE=4194304 # Limit media file size when uploading. For video should probably be greater +RVD_HTTP_TIMEOUT='' # Timeout (ms) for http connections in rvd http client. It mainly affects connections to restcomm (create calls, fetch account etc.). It does not affect ES. + + +#RMS pool size (Un-comment the resource that you want to set the pool size) +#RMS pool size (Should calculated from number of concurrent calls expected). +#RESOURCE_IVR=50 #max conc calls * 2 +#RESOURCE_CNF=50 #max concurrent calls +#RESOURCE_Bridge=50 #max concurrent calls +#RESOURCE_Relay=0 #Not used + +#RestComm Monitoring +#Enabling following means that there is Graylog server running somewhere as well. +GRAYLOG_SERVER="" #IP of the Graylog server to send data. To disable please use empty string +SERVERLABEL="" #RestComm server Label, used to recognise server at Graylog server. +HD_MONITOR=false #Enable HD usage monitoring. +RCJVM_MONITOR=false #Enable JVM (Memory, CPU) usage monitoring for RC. Make sure that $JAVA_HOME/lib/tools.jar exist +RMSJVM_MONITOR=false #Enable JVM (Memory, RAM, CPU) usage monitoring for RMS. Make sure that $JAVA_HOME/lib/tools.jar exist +RAM_MONITOR=false #Enable overall RAM system monitoring. + +#Management User/Password configuration. Used for RestComm statistics consultation (Graylog). +#Jboss Management interface. More info https://docs.jboss.org/author/display/AS7/Management+resources +#Used for RestComm statistics consultation (Graylog). +MGMT_USER='' #Management Interface User configuration. +MGMT_PASS='' #Management Interface Password configuration. + +#Other +#Other General configuration Options +#Directory where HSQL database will exist. If leave empty default value will be used. +#Default: leave empty. +HSQL_DIR='' +#Set Adminitrator User & Password when RestComm run first time. +#If not set default User ("adminitrator@company.com") will be used. +INITIAL_ADMIN_USER='' +#If not set default password ("RestComm") will be used. +INITIAL_ADMIN_PASSWORD='' +#SNI is to be an equivalent of Virtual Hosting but in HTTPS. +#It allows many different domains to be served over a single IP. +#Used in some cases that ES of RVD is not working. (Issue #725) +SSLSNI=TRUE #Enable/disable SNI (Server Name Indication). +#USSD GATEWAY CONFIGURATION +USSDGATEWAYURI='' +USSDGATEWAYUSER='' +USSDGATEWAYPASSWORD='' +#Used to set HTTP Response timeout for RC to download the RCML. +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 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 new file mode 100755 index 0000000000..e8c2d7ee1d --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-SecureSSL.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env bash + +## +## Description: Configures RestComm +## Author: Lefteris Banos (eleftherios.banos@telestax.com) +## + +# VARIABLES +RESTCOMM_BIN=$RESTCOMM_HOME/bin +RESTCOMM_DARS=$RESTCOMM_HOME/standalone/configuration/dars +RESTCOMM_CONF=$RESTCOMM_HOME/standalone/configuration +RESTCOMM_DEPLOY=$RESTCOMM_HOME/standalone/deployments/restcomm.war + +###Functions for SECURESSL=false### +#Disable HTTPS when SECURESSL=false for RC. +NoSslRestConf(){ + FILE=$RESTCOMM_CONF/standalone-sip.xml + sed -e "s//<\!--connector name=\"https\" \1>/" \ + -e "s/<\/connector>/<\/connector-->/" $FILE > $FILE.bak + mv $FILE.bak $FILE + sed -e "s/<.*connector name=\"http\".*>/ /" $FILE > $FILE.bak + mv $FILE.bak $FILE + + sed -i "s|SSL_ENABLED=.*|SSL_ENABLED=false|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|SSL_KEYSTORE=.*|SSL_KEYSTORE=restcomm.jks|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|SSL_PASSWORD=.*|SSL_PASSWORD=changeme|" $RESTCOMM_BIN/restcomm/mediaserver.conf +} + +####funcitions for SECURESSL="SELF" || SECURESSL="AUTH" #### +#HTTPS configuration. +#Usage of certificate. +SslRestCommConf(){ + FILE=$RESTCOMM_CONF/standalone-sip.xml + echo "Will properly configure HTTPS Connector "; + FILERESTCOMMXML=$BASEDIR/standalone/deployments/restcomm.war/WEB-INF/web.xml + FILEMANAGERXML=$BASEDIR/standalone/deployments/restcomm-management.war/WEB-INF/web.xml + FILERVDXML=$BASEDIR/standalone/deployments/restcomm-rvd.war/WEB-INF/web.xml + FILEOLYMPUSXML=$BASEDIR/standalone/deployments/olympus.war/WEB-INF/web.xml + #Disable HTTP if set to true. + if [[ "$DISABLE_HTTP" == "true" || "$DISABLE_HTTP" == "TRUE" ]]; then + echo "DISABLE_HTTP is '$DISABLE_HTTP'. Will disable HTTP Connector" + sed -e "s/<.*connector name=\"http\".*>/<\!--connector name=\"http\" protocol=\"HTTP\/1.1\" scheme=\"http\" socket-binding=\"http\"-->/" $FILE > $FILE.bak + mv $FILE.bak $FILE + + grep -q '' $FILERESTCOMMXML && sed -e "s///" $FILERESTCOMMXML.bak > $FILERESTCOMMXML + grep -qs '' $FILEMANAGERXML && sed -e "s///" $FILEMANAGERXML.bak > $FILEMANAGERXML + grep -q '' $FILERVDXML && sed -e "s///" $FILERVDXML.bak > $FILERVDXML + grep -q '' $FILEOLYMPUSXML && sed -e "s///" $FILEOLYMPUSXML.bak > $FILEOLYMPUSXML + + elif [[ "$DISABLE_HTTP" == "REDIRECT" || "$DISABLE_HTTP" == "redirect" ]]; then + sed -e "s/<.*connector name=\"http\".*>//" $FILE > $FILE.bak + mv $FILE.bak $FILE + if [ ! -d "$BASEDIR/standalone/deployments/restcomm-management.war" ]; then + mkdir $BASEDIR/standalone/deployments/restcomm-management-exploded.war + unzip -q $BASEDIR/standalone/deployments/restcomm-management.war -d $BASEDIR/standalone/deployments/restcomm-management-exploded.war/ + rm -f $BASEDIR/standalone/deployments/restcomm-management.war + mv -f $BASEDIR/standalone/deployments/restcomm-management-exploded.war $BASEDIR/standalone/deployments/restcomm-management.war + fi + + sed -e "s//<\/security-constraint>/" $FILERESTCOMMXML.bak > $FILERESTCOMMXML + sed -e "s//<\/security-constraint>/" $FILEMANAGERXML.bak > $FILEMANAGERXML + sed -e "s//<\/security-constraint>/" $FILERVDXML.bak > $FILERVDXML + sed -e "s//<\/security-constraint>/" $FILEOLYMPUSXML.bak > $FILEOLYMPUSXML + + else + sed -e "s/<.*connector name=\"http\".*>/ /" $FILE > $FILE.bak + mv $FILE.bak $FILE + + grep -q '' $FILERESTCOMMXML && sed -e "s///" $FILERESTCOMMXML.bak > $FILERESTCOMMXML + grep -qs '' $FILEMANAGERXML && sed -e "s///" $FILEMANAGERXML.bak > $FILEMANAGERXML + grep -q '' $FILERVDXML && sed -e "s///" $FILERVDXML.bak > $FILERVDXML + grep -q '' $FILEOLYMPUSXML && sed -e "s///" $FILEOLYMPUSXML.bak > $FILEOLYMPUSXML + + fi + #If File contains path, or just the name. + if [[ "$TRUSTSTORE_FILE" = /* ]]; then + CERTIFICATION_FILE=$TRUSTSTORE_FILE + else + CERTIFICATION_FILE="\\\${jboss.server.config.dir}/$TRUSTSTORE_FILE" + fi + #enable HTTPS and certificate file. + #Cipher `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA` removed because it enables non-secure cipher ECDHE-RSA-DES-CBC3-SHA + echo "Will use trust store at location: $CERTIFICATION_FILE" + sed -e "s/<\!--connector name=\"https\" \(.*\)>//" \ + -e "s|||" \ + -e "s/<\/connector-->/<\/connector>/" $FILE > $FILE.bak + mv $FILE.bak $FILE + echo "Properly configured HTTPS Connector to use trustStore file $CERTIFICATION_FILE" +} + +#If self-sighned create certificate. +#else use authorized. +CertConfigure(){ + #Certificate setup (Authority certificate or self-signed) + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + if [ "$SECURESSL" = "AUTH" ]; then + echo "Authorized certificate is used" + elif [ "$SECURESSL" = "SELF" ]; then + echo "TRUSTSTORE_FILE is not provided but SECURE is TRUE. We will create and configure self signed certificate" + + sed -e "s/.*<\/ssl-mode>/allowall<\/ssl-mode>/" $FILE > $FILE.bak #When Self-signed used ssl-mode must set to "allowall" + mv $FILE.bak $FILE + + if [[ "$TRUSTSTORE_FILE" = /* ]]; then + TRUSTSTORE_LOCATION=$TRUSTSTORE_FILE + else + TRUSTSTORE_LOCATION=$RESTCOMM_HOME/standalone/configuration/$TRUSTSTORE_FILE + fi + + echo "TRUSTSTORE_LOCATION: $TRUSTSTORE_LOCATION" + echo "PUBLIC_IP: $PUBLIC_IP" + echo "RESTCOMM_HOSTNAME: $RESTCOMM_HOSTNAME" + #Use HOSTNAME to create certificate is used. Else use STATIC_ADDRESS + if [ -n "$RESTCOMM_HOSTNAME" ]; then + HOSTNAME="${RESTCOMM_HOSTNAME}" + keytool -genkey -alias $TRUSTSTORE_ALIAS -keyalg RSA -keystore $TRUSTSTORE_LOCATION -dname "CN=$HOSTNAME" -storepass $TRUSTSTORE_PASSWORD -keypass $TRUSTSTORE_PASSWORD + else + HOSTNAME="${PUBLIC_IP}" + keytool -genkey -alias $TRUSTSTORE_ALIAS -keyalg RSA -keystore $TRUSTSTORE_LOCATION -dname "CN=restcomm" -ext san=ip:"$HOSTNAME" -storepass $TRUSTSTORE_PASSWORD -keypass $TRUSTSTORE_PASSWORD + fi + echo "The generated truststore file at $TRUSTSTORE_LOCATION " + fi + + #Final necessary configuration. Protocols permitted, etc. + grep -q 'ephemeralDHKeySize' $RESTCOMM_BIN/standalone.conf || sed -i "s|-Djava.awt.headless=true|& -Djdk.tls.ephemeralDHKeySize=2048|" $RESTCOMM_BIN/standalone.conf + grep -q 'https.protocols' $RESTCOMM_BIN/standalone.conf || sed -i "s|-Djava.awt.headless=true|& -Dhttps.protocols=TLSv1.1,TLSv1.2|" $RESTCOMM_BIN/standalone.conf +} + +#SIP-Servlets configuration for HTTPS. +#For both Self-signed and Authorized certificate. +MssStackConf(){ + FILE=$RESTCOMM_CONF/mss-sip-stack.properties + + 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 + TRUSTSTORE_LOCATION=$TRUSTSTORE_FILE + else + TRUSTSTORE_LOCATION=$RESTCOMM_HOME/standalone/configuration/$TRUSTSTORE_FILE + fi + + #check for port offset + local HTTPS_PORT=$((HTTPS_PORT + PORT_OFFSET)) + + #https://github.com/RestComm/Restcomm-Connect/issues/2606 + sed -i '/org.mobicents.ha.javax.sip.LOCAL_SSL_PORT=.*/ a \ + \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"'\ + \javax.net.ssl.trustStore='"$TRUSTSTORE_LOCATION"'\ + \javax.net.ssl.keyStoreType=JKS\ + ' $RESTCOMM_CONF/mss-sip-stack.properties +} + + +#SIP-Servlets configuration for HTTPS. +#For both Self-signed and Authorized certificate. +SslRMSConf(){ + if [[ "$MANUAL_SETUP" == "false" || "$MANUAL_SETUP" == "FALSE" ]]; then + + if [[ "$TRUSTSTORE_FILE" = /* ]]; then + CERTIFICATION_FILE=$TRUSTSTORE_FILE + else + CERTIFICATION_FILE="$RESTCOMM_CONF/$TRUSTSTORE_FILE" + fi + + sed -i "s|SSL_ENABLED=.*|SSL_ENABLED=true|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|SSL_KEYSTORE=.*|SSL_KEYSTORE=${CERTIFICATION_FILE}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|SSL_PASSWORD=.*|SSL_PASSWORD=${TRUSTSTORE_PASSWORD}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + fi +} + +# MAIN +echo 'RestComm SSL Configuring ...' + +if [[ "$SECURESSL" = "SELF" || "$SECURESSL" = "AUTH" ]]; then + if [[ -z $TRUSTSTORE_ALIAS || -z $TRUSTSTORE_PASSWORD || -z $TRUSTSTORE_FILE ]]; then + echo 'Need to set all: TRUSTSTORE_ALIAS, TRUSTSTORE_PASSWORD,TRUSTSTORE_FILE ' + else + echo "SECURE $SECURESSL" + SslRestCommConf + CertConfigure + MssStackConf + SslRMSConf + fi +elif [[ "$SECURESSL" == "false" || "$SECURESSL" == "FALSE" ]]; then + NoSslRestConf +else + echo "Allowed values for SECURESSL: SELF, AUTH, FALSE" +fi 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-dialogic-xms.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dialogic-xms.sh new file mode 100755 index 0000000000..4b4a8d6403 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dialogic-xms.sh @@ -0,0 +1,57 @@ +#!/bin/bash +## Description: Configures Dialogic XMS +## Author : Henrique Rosa (henrique.rosa@telestax.com) + +RESTCOMM_STANDALONE=$RESTCOMM_HOME/standalone +RESTCOMM_DEPLOY=$RESTCOMM_STANDALONE/deployments/restcomm.war + +## Description: Elects Dialogic XMS as the active Media Server for RestComm +activateXMS() { + restcomm_conf=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + ms_address="$1" + + sed -e "// { + N; s|.*<\/compatibility>|$MS_COMPATIBILITY_MODE<\/compatibility>| + N; s||| + N; s|
.*<\/address>|
$ms_address<\/address>| + }" $restcomm_conf > $restcomm_conf.bak + mv -f $restcomm_conf.bak $restcomm_conf + echo '...activated Dialogic XMS...' +} + +fetchExternalResources() { + if [[ "$MS_COMPATIBILITY_MODE" == "xms" ]]; then + + echo "Checking required libraries ..." + + if [ -f $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib/dialogic309-3.2-snapshot-jboss.jar ]; then + echo "JSR309 library ready" + else + echo "Downloading JSR309 library ..." + cd $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib + wget -O dialogic309-3.2-snapshot-jboss.jar https://www.dialogic.com/files/jsr-309/3.2GA/3.2Snapshot/dialogic309-3.2-snapshot-jboss.jar + fi + + if [ -f $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib/dialogicsmiltypes-3.2-GA-14621.jar ]; then + echo "SMIL Types library ready" + else + echo "Downloading SMIL Types library ..." + cd $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib + wget -O dialogicsmiltypes-3.2-GA-14621.jar https://www.dialogic.com/files/jsr-309/3.2GA/dialogicsmiltypes-3.2-GA-14621.jar + fi + + if [ -f $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib/dialogicmsmltypes-3.2-GA-14621.jar ]; then + echo "MSML Types library ready" + else + echo "Downloading SMIL Types library ..." + cd $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/lib + wget -O dialogicmsmltypes-3.2-GA-14621.jar https://www.dialogic.com/files/jsr-309/3.2GA/dialogicmsmltypes-3.2-GA-14621.jar + fi + fi +} + +#MAIN +echo "Configuring Dialogic XMS...MS_MODE: $MS_COMPATIBILITY_MODE" +activateXMS $MS_ADDRESS +fetchExternalResources +echo '...finished configuring Dialogic XMS!' diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-jboss-as.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-jboss-as.sh new file mode 100755 index 0000000000..c324c99337 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-jboss-as.sh @@ -0,0 +1,18 @@ +#! /bin/bash +## +## Description: Configures JBoss AS +## Author : Henrique Rosa (henrique.rosa@telestax.com) +## + +## FUNCTIONS +disableSplashScreen() { + FILE="$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml" + sed -e 's|enable-welcome-root=".*"|enable-welcome-root="false"|' $FILE > $FILE.bak + mv -f $FILE.bak $FILE +} + +## MAIN +echo 'Configuring JBoss AS...' +disableSplashScreen +echo '...disabled JBoss splash screen...' +echo 'Finished configuring JBoss AS!' \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-load-balancer.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-load-balancer.sh new file mode 100755 index 0000000000..77b5c56486 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-load-balancer.sh @@ -0,0 +1,47 @@ +#! /bin/bash +## +## Description: Configures SIP Load Balancer +## Author : Henrique Rosa (henrique.rosa@telestax.com) +## Author : Pavel Slegr (pavel.slegr@telestax.com) +## Author : Charles Roufay (charles.roufay@telestax.com) +## +## Last update: 22/03/2016 +## Change Log: Move away from Telestax Proxy and configure LB from restcomm.conf +## FUNCTIONS +## +## +## +## +configSipStack() { + lb_sipstack_file="$RESTCOMM_HOME/standalone/configuration/mss-sip-stack.properties" + + #delete additional connectors if any added to erlier run of the script. + if grep -q "## lb-configuration ##" $lb_sipstack_file + then + echo "Additional Connectors Created earlier, going to delete the connectors" + sed '/## lb-configuration ##/,/## lb-configuration ##/d' $lb_sipstack_file > $lb_sipstack_file.bak + mv $lb_sipstack_file.bak $lb_sipstack_file + else + echo "LB was not configured earlier" + fi + + if [ "$ACTIVATE_LB" == "true" ] || [ "$ACTIVATE_LB" == "TRUE" ]; then + if [ -z "$LB_INTERNAL_IP" ]; then + LB_INTERNAL_IP=$LB_PUBLIC_IP + fi + sed -e "/Mobicents Load Balancer/a\ + ## lb-configuration ##\n\ + gov.nist.javax.sip.PATCH_SIP_WEBSOCKETS_HEADERS=false\n\ + org.mobicents.ha.javax.sip.REACHABLE_CHECK=false\n\ + org.mobicents.ha.javax.sip.LoadBalancerHeartBeatingServiceClassName=org.mobicents.ha.javax.sip.MultiNetworkLoadBalancerHeartBeatingServiceImpl\n\ + ## lb-configuration ##" $lb_sipstack_file > $lb_sipstack_file.bak + + mv $lb_sipstack_file.bak $lb_sipstack_file + echo 'Load Balancer has been activated and mss-sip-stack.properties file updated' + fi +} + +## MAIN +configSipStack + + diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-logs.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-logs.sh new file mode 100755 index 0000000000..5eb9ee7934 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-logs.sh @@ -0,0 +1,81 @@ +#!/bin/bash +## +## Description: Configures RestComm && RMS logs level +## Authos: Lefteris Banos (eleftherios.banos@telestax.com) + +# VARIABLES +RESTCOMM_BIN=$RESTCOMM_HOME/bin +RESTCOMM_CONF=$RESTCOMM_HOME/standalone/configuration + + +check_if_logger_exist(){ +FILE=$RESTCOMM_CONF/standalone-sip.xml + #delete additional bindings if any added to erlier run of the script. + echo + if grep -q "${1}" $FILE + then + echo "Logger exist" + else + echo "Need to add logger ${1}" + sed -i "//i \\n\\n" $FILE + fi + +} + +configure_RC_component_log(){ + check_if_logger_exist $1 + sed -i "// {N; s///}" $RESTCOMM_CONF/standalone-sip.xml +} + +configure_RC_logs(){ + sed -i "/ / { + N; s||| + }" $RESTCOMM_CONF/standalone-sip.xml +} + +config_on_thefly(){ + FILE=$RESTCOMM_BIN/restcomm/set-log-level.sh + MNGMTPORT=$((9999 + PORT_OFFSET)) + sed -i "s|jboss-cli.sh --connect controller=.*|jboss-cli.sh --connect controller=$BIND_ADDRESS:${MNGMTPORT} --file=\"\$CLIFILE\"|" $FILE +} + +config_AKKA_logs(){ + FILE=$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/classes/application.conf + echo "Update AKKA log level to ${AKKA_LOG_LEVEL}" + sed -i "s|loglevel = \".*\"|loglevel = \"${AKKA_LOG_LEVEL}\"|" $FILE + sed -i "s|stdout-loglevel = \".*\"|stdout-loglevel = \"${AKKA_LOG_LEVEL}\"|" $FILE +} + + +#MAIN +if [ -n "$LOG_LEVEL" ]; then + configure_RC_logs + config_on_thefly + config_AKKA_logs + for i in $( set -o posix ; set | grep ^LOG_LEVEL_COMPONENT_ | sort -rn ); do + component=$(echo ${i} | cut -d = -f1 | cut -d _ -f4 ) + level=$(echo ${i} | cut -d = -f2) + case "$component" in + SIPSERVLET) + COMPONENT=org.mobicents.servlet.sip + ;; + GOVNIST) + COMPONENT=gov.nist + ;; + SIPRESTCOMM) + COMPONENT=org.mobicents.servlet.sip.restcomm + ;; + RESTCOMM) + COMPONENT=org.restcomm.connect + ;; + *) + echo "$component not possible to configure need to add it." + continue + esac + + echo "Configuring log level for: $component -> $level" + configure_RC_component_log "$COMPONENT" "$level" + done + fi + + diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-mysql.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-mysql.sh new file mode 100755 index 0000000000..7478e55e88 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-mysql.sh @@ -0,0 +1,249 @@ +#!/bin/bash +## Description: Enables and configures MySQL datasource +## Params: +## 1. RESTCOMM_VERSION +## Author: Henrique Rosa +## Author: Lefteris Banos + +# VARIABLES +RESTCOMM_DEPLOY=$RESTCOMM_HOME/standalone/deployments/restcomm.war + + +creteMysqlDataSource(){ + if [ -z "$RESTCOMM_HOME" ]; then + echo "RESTCOMM_HOME is not defined. Please setup this environment variable and try again." + exit 1 + fi + + # Variables + MYSQLDB_MODULE=$RESTCOMM_HOME/modules/system/layers/base/com/mysql/main + STANDALONE_SIP=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml + + # Download and install MariaDB driver as a JBoss module + mkdir -p $MYSQLDB_MODULE + if [ ! -f $MYSQLDB_MODULE/mysql-connector-java-5.1.36.jar ]; then + echo "Mysql driver not found!" + wget http://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.36/mysql-connector-java-5.1.36.jar -O /tmp/mysql-connector-java-5.1.36.jar + cp /tmp/mysql-connector-java-5.1.36.jar $MYSQLDB_MODULE + rm -f /tmp/mysql-connector-java-5.1.36.jar + else + echo "Mysql driver already downloaded" + fi + + +cat > $MYSQLDB_MODULE/module.xml << 'EOF' + + + + + + + + + + +EOF + +query=$(grep -q 'driver name=\"com.mysql\"' $STANDALONE_SIP) +if [ $? -eq 0 ]; then + echo "Datasource already populated" +else + echo "Going to populate the datasource" + + if [ -n "$MYSQL_SNDHOST" ]; then + # Update JBoss configuration to create a MariaDB datasource + sed -e '// a\ + \ \ + \ com.mysql.jdbc.Driver\ + \ com.mysql.jdbc.jdbc2.optional.MysqlXADataSource\ + \ ' \ + -e '// a\ + \ \ + \ jdbc:mysql://localhost:3306/restcomm \ + \ | \ + \ false \ + \ com.mysql \ + \ com.mysql.jdbc.Driver \ + \ TRANSACTION_READ_COMMITTED \ + \ \ + \ 5 \ + \ 50 \ + \ \ + \ \ + \ username \ + \ password \ + \ \ + \ \ + \ 100 \ + \ \ + \ \ + \ \ + \ true \ + \ \ + \ \ + \ select 1 \ + \ \ + \ ' $STANDALONE_SIP > $STANDALONE_SIP.bak + mv $STANDALONE_SIP.bak $STANDALONE_SIP + + else + # Update JBoss configuration to create a MariaDB datasource + sed -e '// a\ + \ \ + \ com.mysql.jdbc.Driver\ + \ com.mysql.jdbc.jdbc2.optional.MysqlXADataSource\ + \ ' \ + -e '// a\ + \ \ + \ jdbc:mysql://localhost:3306/restcomm \ + \ com.mysql \ + \ TRANSACTION_READ_COMMITTED \ + \ \ + \ 100 \ + \ 200 \ + \ \ + \ \ + \ username \ + \ password \ + \ \ + \ \ + \ 100 \ + \ \ + \ \ + \ ' $STANDALONE_SIP > $STANDALONE_SIP.bak + mv $STANDALONE_SIP.bak $STANDALONE_SIP + fi +fi +} + +## Description: Configures MyBatis for MySQL +## Parameters : none +configMybatis() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/mybatis.xml + + grep -q '' $FILE || sed -i '// a \ + \ \ + \ \ + \ \ + \ \ + \ \ + \ \ + ' $FILE + + sed -e '// s|default=".*"|default="mysql"|' $FILE > $FILE.bak + mv $FILE.bak $FILE + echo 'Activated mybatis environment for MySQL'; +} + +configureMySQLDataSource() { + FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml + + if [ -n "$5" ]; then + #DB failover configuration. + sed -e "s|.*|jdbc:mysql://$1:3306/$4\|jdbc:mysql://$5:3306/$4|g" $FILE > $FILE.bak + else + # Update DataSource + sed -e "s|.*|jdbc:mysql://$1:3306/$4|g" $FILE > $FILE.bak + fi + mv $FILE.bak $FILE + sed -e "s|.*|$2|g" $FILE > $FILE.bak + mv $FILE.bak $FILE + sed -e "s|.*|$3|g" $FILE > $FILE.bak + mv $FILE.bak $FILE + echo 'Updated MySQL DataSource Configuration' +} + +## Description: Enables MySQL Datasource while disabling the remaining +## Parameters : none +enableDataSource() { + FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml + + # Disable all datasources but MySQL + sed -e '/ $FILE.bak + + mv $FILE.bak $FILE + echo 'Enabled MySQL datasource' +} + +## Description: Configures RestComm DAO manager to use MySQL +## Params: none +configDaoManager() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/dao-manager.xml + + sed -e "s|.*||g" $FILE > $FILE.bak + mv $FILE.bak $FILE + sed -e "s|.*|\${restcomm:home}/WEB-INF/scripts/mariadb/sql|g" $FILE > $FILE.bak + mv $FILE.bak $FILE + + echo 'Configured MySQL Dao Manager for MySQL' +} + +## Description: Set Password for Adminitrator@company.com user. Only for fresh installation. +initUserPassword(){ + SQL_FILE=$RESTCOMM_DEPLOY/WEB-INF/scripts/mariadb/init.sql + if [ -n "$INITIAL_ADMIN_USER" ]; then + # change admin user + if grep -q "uninitialized" $SQL_FILE; then + echo "Update Admin user" + sed -i "s/administrator@company.com/${INITIAL_ADMIN_USER}/g" $SQL_FILE + else + echo "Adminitrator User Already changed" + fi + fi + + if [ -n "$INITIAL_ADMIN_PASSWORD" ]; then + echo "change admin password" + if grep -q "uninitialized" $SQL_FILE; then + PASSWORD_ENCRYPTED=`echo -n "${INITIAL_ADMIN_PASSWORD}" | md5sum |cut -d " " -f1` + #echo "Update password to ${INITIAL_ADMIN_PASSWORD}($PASSWORD_ENCRYPTED)" + sed -i "s/uninitialized/active/g" $SQL_FILE + sed -i "s/77f8c12cc7b8f8423e5c38b035249166/$PASSWORD_ENCRYPTED/g" $SQL_FILE + sed -i 's/Date("2012-04-24")/now()/' $SQL_FILE + sed -i 's/Date("2012-04-24")/now()/' $SQL_FILE + # end + else + echo "Adminitrator Password Already changed" + fi + fi +} + +## Description: populated DB with necessary starting point data if not done. +populateDB(){ + #Change script to defined schema + echo "Use RestComm Database:$MYSQL_SCHEMA " + sed -i "s|CREATE DATABASE IF NOT EXISTS .*| CREATE DATABASE IF NOT EXISTS ${MYSQL_SCHEMA};|" $RESTCOMM_DEPLOY/WEB-INF/scripts/mariadb/init.sql + sed -i "s|USE .*|USE ${MYSQL_SCHEMA};|" $RESTCOMM_DEPLOY/WEB-INF/scripts/mariadb/init.sql + + if mysql -u $2 -p$3 -h $1 -e "SELECT * FROM \`$4\`.restcomm_clients;" &>/dev/null ; then + # Update config settings + echo "Database already populated" + else + echo "Database not populated, importing schema and updating config file" + FILE=$RESTCOMM_DEPLOY/WEB-INF/scripts/mariadb/init.sql + mysql -u $2 -p$3 -h $1 < $FILE + mysql -u $2 -p$3 -h $1 --execute='show databases;' + mysql -u $2 -p$3 -h $1 --execute='show tables;' $4; + echo "Database population done" + fi +} + +# MAIN +if [[ "$ENABLE_MYSQL" == "true" || "$ENABLE_MYSQL" == "TRUE" ]]; then + if [[ -z $MYSQL_HOST || -z $MYSQL_USER || -z $MYSQL_PASSWORD || -z $MYSQL_SCHEMA ]]; then + echo 'one or more variables are undefined' + echo 'Not possible to continue with Mysql configuration' + exit 1 + else + echo "Configuring MySQL datasource... $MYSQL_HOST $MYSQL_SCHEMA $MYSQL_USER $MYSQL_SNDHOST" + creteMysqlDataSource + enableDataSource + configMybatis + configDaoManager + configureMySQLDataSource $MYSQL_HOST $MYSQL_USER $MYSQL_PASSWORD $MYSQL_SCHEMA $MYSQL_SNDHOST + initUserPassword + populateDB $MYSQL_HOST $MYSQL_USER $MYSQL_PASSWORD $MYSQL_SCHEMA + echo 'Finished configuring MySQL datasource!' + fi +fi \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-olympus.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-olympus.sh new file mode 100755 index 0000000000..24f3f93115 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-olympus.sh @@ -0,0 +1,46 @@ +#!/bin/bash +## +## Description: Configures RestComm +## Author: Lefteris Banos (eleftherios.banos@telestax.com) +## + +BASEDIR=$RESTCOMM_HOME + +if [ ! -d "$BASEDIR/standalone/deployments/olympus.war" ]; then + mkdir $BASEDIR/standalone/deployments/olympus-exploded.war + unzip -q $BASEDIR/standalone/deployments/olympus.war -d $BASEDIR/standalone/deployments/olympus-exploded.war/ + rm -f $BASEDIR/standalone/deployments/olympus.war + mv -f $BASEDIR/standalone/deployments/olympus-exploded.war $BASEDIR/standalone/deployments/olympus.war +fi + +# Set Olympus ports +olympusPortConf(){ +FILE=$BASEDIR/standalone/deployments/olympus.war/resources/xml/olympus.xml + +# Check for Port Offset + local SIP_PORT_WS=$((SIP_PORT_WS + PORT_OFFSET)) + local SIP_PORT_WSS=$((SIP_PORT_WSS + PORT_OFFSET)) + + if [ -z "$SECURESSL" ] || [ "$SECURESSL" == "false" ] || [ "$SECURESSL" == "FALSE" ]; then + xmlstarlet ed -L -P -u "/olympus/server/@secure" -v "false" $FILE + else + xmlstarlet ed -L -P -u "/olympus/server/@secure" -v "true" $FILE + fi + + if [ "$ACTIVATE_LB" == "true" ] || [ "$ACTIVATE_LB" == "TRUE" ]; then + xmlstarlet ed -L -P -u "/olympus/server/port" -v ${LB_EXTERNAL_PORT_WS} $FILE + xmlstarlet ed -L -P -u "/olympus/server/secure-port" -v ${LB_EXTERNAL_PORT_WSS} $FILE + else + xmlstarlet ed -L -P -u "/olympus/server/port" -v ${SIP_PORT_WS} $FILE + xmlstarlet ed -L -P -u "/olympus/server/secure-port" -v ${SIP_PORT_WSS} $FILE + fi + +} + + + + +# MAIN +echo 'Configuring Olympus...' +#Reload Variables +olympusPortConf 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 new file mode 100755 index 0000000000..92397c287e --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh @@ -0,0 +1,893 @@ +#!/bin/bash +## +## Description: Configures RestComm +## Author: Henrique Rosa (henrique.rosa@telestax.com) +## Author: Pavel Slegr (pavel.slegr@telestax.com) +## Author: Maria Farooq (maria.farooq@telestax.com) +## + +# VARIABLES +RESTCOMM_BIN=$RESTCOMM_HOME/bin +RESTCOMM_DARS=$RESTCOMM_HOME/standalone/configuration/dars +RESTCOMM_CONF=$RESTCOMM_HOME/standalone/configuration +RESTCOMM_DEPLOY=$RESTCOMM_HOME/standalone/deployments/restcomm.war +RVD_DEPLOY_PATH=$RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war + +## FUNCTIONS + +## Description: Configures Java Options for Application Server +## Parameters : none +configRCJavaOpts() { + FILE=$RESTCOMM_BIN/standalone.conf + echo "RestComm java options with: $RC_JAVA_OPTS" + sed -e "/if \[ \"x\$JAVA_OPTS\" = \"x\" \]; then/ { + N; s|JAVA_OPTS=.*|JAVA_OPTS=\"$RC_JAVA_OPTS\"| + }" $FILE > $FILE.bak + mv $FILE.bak $FILE +} + +## Description: Updates RestComm configuration file +## Parameters : 1.STATIC_ADDRESS +configRestcomm() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + static_address="$1" + + sed -i "s|<\!--.*.*<\/external-ip>.*-->|$static_address<\/external-ip>|" $FILE + sed -i "s|.*<\/external-ip>|$static_address<\/external-ip>|" $FILE + + sed -i "s||$static_address<\/external-ip>|" $FILE + + echo 'Updated RestComm configuration' + + #If "STRICT" no self-signed certificate is permitted. + if [ "$SSL_MODE" == "strict" ] || [ "$SSL_MODE" == "STRICT" ]; then + sed -e "s/.*<\/ssl-mode>/strict<\/ssl-mode>/g;s//strict<\/ssl-mode>/g" $FILE > $FILE.bak + mv $FILE.bak $FILE + else + sed -e "s/.*<\/ssl-mode>/allowall<\/ssl-mode>/g;s//allowall<\/ssl-mode>/g" $FILE > $FILE.bak + mv $FILE.bak $FILE + fi + + #Configure RESTCOMM_HOSTNAME at restcomm.xml. If not set "STATIC_ADDRESS" will be used. + if [ -n "$RESTCOMM_HOSTNAME" ]; then + echo "HOSTNAME $RESTCOMM_HOSTNAME" + + sed -i "s|.*<\/hostname>|${RESTCOMM_HOSTNAME}<\/hostname>|" $RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i "s||${RESTCOMM_HOSTNAME}<\/hostname>|" $RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + if ! grep "${BIND_ADDRESS}.*${RESTCOMM_HOSTNAME}" /etc/hosts ; then + if hash host 2>/dev/null; then + if ! host ${RESTCOMM_HOSTNAME} > /dev/null + then + echo "${BIND_ADDRESS} ${RESTCOMM_HOSTNAME}" >> /etc/hosts + fi + else + echo "INFO: \"host\" programm does not exist ('dnsutils' package) please make sure that used hostname has a valid DNS resolution." + echo "INFO:IF not add the necessary hostname Ip resolution at /etc/hosts file: e.g echo RestC0mm_BIND_IP RESTCOMM_HOSTNAME >> /etc/hosts " + fi +fi + else + sed -i "s|.*<\/hostname>|${PUBLIC_IP}<\/hostname>|" $RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i "s||${PUBLIC_IP}<\/hostname>|" $RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + fi +} +## Description: OutBoundProxy configuration. +configOutboundProxy(){ + echo "Configure outbound-proxy" + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i "s|.*<\/outbound-proxy-uri>|$OUTBOUND_PROXY<\/outbound-proxy-uri>|" $FILE + sed -i "s|.*<\/outbound-proxy-user>|$OUTBOUND_PROXY_USERNAME<\/outbound-proxy-user>|" $FILE + sed -i "s|.*<\/outbound-proxy-password>|$OUTBOUND_PROXY_PASSWORD<\/outbound-proxy-password>|" $FILE + + sed -i "s||$OUTBOUND_PROXY<\/outbound-proxy-uri>|" $FILE + sed -i "s||$OUTBOUND_PROXY_USERNAME<\/outbound-proxy-user>|" $FILE + sed -i "s||$OUTBOUND_PROXY_PASSWORD<\/outbound-proxy-password>|" $FILE +} +## Description: Push notification server configuration. +configPushNotificationServer() { + echo "Configure push-notification-server" + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + sed -i "s|.*<\/push-notification-server-enabled>|$PUSH_NOTIFICATION_SERVER_ENABLED<\/push-notification-server-enabled>|" $FILE + sed -i "s|.*<\/push-notification-server-url>|$PUSH_NOTIFICATION_SERVER_URL<\/push-notification-server-url>|;" $FILE + sed -i "s|.*<\/push-notification-server-delay>|$PUSH_NOTIFICATION_SERVER_DELAY<\/push-notification-server-delay>|" $FILE + + sed -i "s||$PUSH_NOTIFICATION_SERVER_ENABLED<\/push-notification-server-enabled>|" $FILE + sed -i "s||$PUSH_NOTIFICATION_SERVER_URL<\/push-notification-server-url>|" $FILE + sed -i "s||$PUSH_NOTIFICATION_SERVER_DELAY<\/push-notification-server-delay>|" $FILE +} +## Description: Configures Voip Innovations Credentials +## Parameters : 1.Login +## 2.Password +## 3.Endpoint +configVoipInnovations() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$3| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + N; s||$3| + }" $FILE + + echo 'Configured Voip Innovation credentials' +} + +## Description: PROVISION MANAGER configuration. +# MANAGERS : VI (Voip innovations),NX (nexmo),VB (Voxbone), BW(Bandwidth). +configDidProvisionManager() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + if [[ "$PROVISION_PROVIDER" == "VI" || "$PROVISION_PROVIDER" == "vi" ]]; then + sed -e "s|phone-number-provisioning class=\".*\"|phone-number-provisioning class=\"org.restcomm.connect.provisioning.number.vi.VoIPInnovationsNumberProvisioningManager\"|" $FILE > $FILE.bak + + mv $FILE.bak $FILE + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$3| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + N; s||$3| + }" $FILE + + sed -i "s|.*<\/outboudproxy-user-at-from-header>|"false"<\/outboudproxy-user-at-from-header>|" $FILE + sed -i "s||"false"<\/outboudproxy-user-at-from-header>|" $FILE + echo 'Configured Voip Innovation credentials' + else + if [[ "$PROVISION_PROVIDER" == "BW" || "$PROVISION_PROVIDER" == "bw" ]]; then + sed -e "s|phone-number-provisioning class=\".*\"|phone-number-provisioning class=\"org.restcomm.connect.provisioning.number.bandwidth.BandwidthNumberProvisioningManager\"|" $FILE > $FILE.bak + + mv $FILE.bak $FILE + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$6| + N; s|.*|$4| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + N; s||$6| + N; s||$4| + }" $FILE + + sed -i "s|.*<\/outboudproxy-user-at-from-header>|"false"<\/outboudproxy-user-at-from-header>|" $FILE + sed -i "s||"false"<\/outboudproxy-user-at-from-header>|" $FILE + echo 'Configured Bandwidth credentials' + else + if [[ "$PROVISION_PROVIDER" == "NX" || "$PROVISION_PROVIDER" == "nx" ]]; then + echo "Nexmo PROVISION_PROVIDER" + sed -i "s|phone-number-provisioning class=\".*\"|phone-number-provisioning class=\"org.restcomm.connect.provisioning.number.nexmo.NexmoPhoneNumberProvisioningManager\"|" $FILE + + if [[ -z "$8" ]]; then + sed -i "// { + N; s||| + N; s||| + N; s||| + N; s||| + }" $FILE + else + sed -i "// { + N; s||| + N; s||| + N; s||| + N; s||| + }" $FILE + fi + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + N + N; s|.*|$7| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + N + N; s||$7| + }" $FILE + + sed -i "s|.*<\/outboudproxy-user-at-from-header>|"true"<\/outboudproxy-user-at-from-header>|" $FILE + sed -i "s||"true"<\/outboudproxy-user-at-from-header>|" $FILE + + else + if [[ "$PROVISION_PROVIDER" == "VB" || "$PROVISION_PROVIDER" == "vb" ]]; then + echo "Voxbone PROVISION_PROVIDER" + sed -i "s|phone-number-provisioning class=\".*\"|phone-number-provisioning class=\"org.restcomm.connect.provisioning.number.voxbone.VoxbonePhoneNumberProvisioningManager\"|" $FILE + + sed -i "// { + N; s||| + N; s||| + N; s||| + N; s||| + }" $FILE + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + }" $FILE + sed -i "// { + N; s||$1| + N; s||$2| + }" $FILE + sed -i "s|.*<\/outboudproxy-user-at-from-header>|"false"<\/outboudproxy-user-at-from-header>|" $FILE + sed -i "s||"false"<\/outboudproxy-user-at-from-header>|" $FILE + + fi + fi + fi + fi +} + +## Description: Configures Fax Service Credentials +## Parameters : 1.Username +## 2.Password +configFaxService() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + }" $FILE + + echo 'Configured Fax Service credentials' +} + +## Description: Configures Sms Aggregator +## Parameters : 1.Outbound endpoint IP +## +configSmsAggregator() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + sed -i "// { + N; s|.*|$2| + N; s|.*|$1| + }" $FILE + + sed -i "// { + N; s||$2| + N; s||$1| + }" $FILE + echo "Configured Sms Aggregator using OUTBOUND PROXY $1" +} + +## Description: Configures Speech Recognizer +## Parameters : 1.iSpeech Key +configSpeechRecognizer() { + if [ -n "$ISPEECH_KEY" ]; then + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + sed -i "// { + N; s||$1| + }" $FILE + + sed -i "// { + N; s||$1| + }" $FILE + + echo 'Configured the Speech Recognizer' + fi +} + +## Description: Configures available speech synthesizers +## Parameters : none +configSpeechSynthesizers() { + if [[ "$TTSSYSTEM" == "voicerss" ]]; then + configVoiceRSS $VOICERSS_KEY + + elif [[ "$TTSSYSTEM" == "awspolly" ]]; then + configAWSPolly $AWS_ACCESS_KEY $AWS_SECRET_KEY $AWS_REGION + + else + configAcapela $ACAPELA_APPLICATION $ACAPELA_LOGIN $ACAPELA_PASSWORD + fi +} + +## Description: Configures Acapela Speech Synthesizer +## Parameters : 1.Application Code +## 2.Login +## 3.Password +configAcapela() { + if [[ -z $ACAPELA_APPLICATION || -z $ACAPELA_LOGIN || -z $ACAPELA_PASSWORD ]]; then + echo '!Please make sure that all necessary settings for acapela are set!' + else + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i 's|||' $FILE + + sed -i "// { + N + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$3| + }" $FILE + + sed -i "// { + N + N; s||$1| + N; s||$2| + N; s||$3| + }" $FILE + + echo 'Configured Acapela Speech Synthesizer' + fi +} + + +## Description: Configures VoiceRSS Speech Synthesizer +## Parameters : 1.API key +configVoiceRSS() { + if [ -n "$VOICERSS_KEY" ]; then + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i 's|||' $FILE + + sed -i "/http:\/\/api.voicerss.org<\/service-root>/ { + N; s|.*|$1| + }" $FILE + + sed -i "/http:\/\/api.voicerss.org<\/service-root>/ { + N; s||$1| + }" $FILE + + echo 'Configured VoiceRSS Speech Synthesizer' + + else + echo 'Please set KEY for VoiceRSS TTS' + fi +} + +## Description: Configures AWS Polly Speech Synthesizer +## Parameters : 1.AWS Access Key +## 2.AWS Secret key +## 3.AWS Region +configAWSPolly() { + if [[ -z $AWS_ACCESS_KEY || -z $AWS_SECRET_KEY || -z $AWS_REGION ]]; then + echo '!Please make sure that all necessary settings for AWS Polly are set!' + else + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i 's|||' $FILE + + sed -i "// { + N + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$3| + }" $FILE + + sed -i "// { + N + N; s||$1| + N; s||$2| + N; s||$3| + }" $FILE + + echo 'Configured AWS Polly Speech Synthesizer' + fi +} + +## Description: Updates RestComm DARS properties for RestComm +## Parameters : none +configDARSProperties() { + FILE=$RESTCOMM_DARS/mobicents-dar.properties + sed -e 's|^ALL=.*|ALL=("RestComm", "DAR\:From", "NEUTRAL", "", "NO_ROUTE", "0")|' $FILE > $FILE.bak + mv $FILE.bak $FILE + echo "Updated mobicents-dar properties" +} + +## Description: Configures TeleStax Proxy +## Parameters : 1.Enabled +## 2.login +## 3.password +## 4.Endpoint +## 5.Proxy IP +configTelestaxProxy() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + enabled="$1" + if [ "$enabled" == "true" ] || [ "$enabled" == "TRUE" ]; then + sed -i "// { + N; s|.*|$1| + N; s|.*|$2| + N; s|.*|$3| + N; s|.*|$4| + N; s|.*|$6| + N; s|.*|http:\/\/$5:2080| + }" $FILE + + sed -i "// { + N; s||$1| + N; s||$2| + N; s||$3| + N; s||$4| + N; s||$6| + N; s||http:\/\/$5:2080| + }" $FILE + + echo 'Enabled TeleStax Proxy' + else + sed -i "// { + N; s|.*|false| + N; s|.*|| + N; s|.*|| + N; s|.*|| + N; s|.*|| + N; s|.*|http:\/\/127.0.0.1:2080| + }" $FILE + + sed -i "// { + N; s||false| + N; s||| + N; s||| + N; s||| + N; s||| + N; s||http:\/\/127.0.0.1:2080| + }" $FILE + + echo 'Disabled TeleStax Proxy' + fi +} + + +## Description: Configures Media Server Manager +## Parameters : 1.Enabled +## 2.private IP +## 3.public IP + +configMediaServerManager() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + bind_address="$1" + ms_address="$2" + ms_external_address="$3" + + #Check for Por Offset + local LOCALMGCP=$((LOCALMGCP + PORT_OFFSET)) + local REMOTEMGCP=$((REMOTEMGCP + PORT_OFFSET)) + + sed -e "s/.*<\/local-address>/$bind_address<\/local-address>/g;s//$bind_address<\/local-address>/g" \ + -e "s/.*<\/local-port>/$LOCALMGCP<\/local-port>/g;s//$LOCALMGCP<\/local-port>/g" \ + -e "s/.*<\/remote-address>/$ms_address<\/remote-address>/g;s//$ms_address<\/remote-address>/g" \ + -e "s/.*<\/remote-port>/$REMOTEMGCP<\/remote-port>/g;s//$REMOTEMGCP<\/remote-port>/g" \ + -e "s/.*<\/response-timeout>/$MGCP_RESPONSE_TIMEOUT<\/response-timeout>/g;s//$MGCP_RESPONSE_TIMEOUT<\/response-timeout>/g" \ + -e "s/<\!--.*.*<\/external-address>.*-->/$ms_external_address<\/external-address>/g;" \ + -e "s/.*<\/external-address>/$ms_external_address<\/external-address>/g;s//$ms_external_address<\/external-address>/g" $FILE > $FILE.bak + + mv $FILE.bak $FILE + echo 'Configured Media Server Manager' +} + +## Description: Configures SMPP Account Details +## Parameters : 1.activate +## 2.systemID +## 3.password +## 4.systemType +## 5.peerIP +## 6.peerPort +## 7.sourceMap +## 8.destinationMap + +configSMPPAccount() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + activate="$1" + systemID="$2" + password="$3" + systemType="$4" + peerIP="$5" + peerPort="$6" + sourceMap="$7" + destinationMap="$8" + + + sed -i "s|||g" $FILE + #Add sourceMap && destinationMap + + + if [ "$activate" == "true" ] || [ "$activate" == "TRUE" ]; then + sed -i "/.*|$systemID| + N; s|.*|$peerIP| + N; s|.*|$peerPort| + N + N + N; s|.*|$password| + N; s|.*|$systemType| + }" $FILE + + sed -i "/$systemID| + N; s||$peerIP| + N; s||$peerPort| + N + N + N; s||$password| + N; s||$systemType| + }" $FILE + + sed -i "s|||" $FILE + echo 'Configured SMPP Account Details' + + else + sed -i "/.*|| + N; s|.*|| + N; s|.*|| + N + N + N; s|.*|| + N; s|.*|| + }" $FILE + + sed -i "/|| + N; s||| + N; s||| + N + N + N; s||| + N; s||| + }" $FILE + + sed -i "s|||" $FILE + echo 'Configured SMPP Account Details' + fi +} + +## Description: Configures RestComm "prompts & cache" URIs +#Mostly used for external MS. +configRestCommURIs() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + #check for port offset + local HTTP_PORT=$((HTTP_PORT + PORT_OFFSET)) + local HTTPS_PORT=$((HTTPS_PORT + PORT_OFFSET)) + + if [ -n "$MS_ADDRESS" ] && [ "$MS_ADDRESS" != "$BIND_ADDRESS" ]; then + if [ "$DISABLE_HTTP" = "true" ]; then + PORT="$HTTPS_PORT" + SCHEME='https' + else + PORT="$HTTP_PORT" + SCHEME='http' + fi + + # STATIC_ADDRESS will be populated by user or script before + REMOTE_ADDRESS="${SCHEME}://${PUBLIC_IP}:${PORT}" + + sed -i "s|.*|$REMOTE_ADDRESS/restcomm/audio<\/prompts-uri>|" $FILE + sed -i "s|.*/cache-uri>|$REMOTE_ADDRESS/restcomm/cache|" $FILE + sed -i "s|.*|$REMOTE_ADDRESS/restcomm/errors|" $FILE + + sed -i "s||$REMOTE_ADDRESS/restcomm/audio<\/prompts-uri>|" $FILE + sed -i "s||$REMOTE_ADDRESS/restcomm/cache|" $FILE + sed -i "s||$REMOTE_ADDRESS/restcomm/errors|" $FILE + + echo "Updated prompts-uri cache-uri error-dictionary-uri External MSaddress for " + fi + echo 'Configured RestCommURIs' +} + +## Description: Specify the path where Recordings are saved. +updateRecordingsPath() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + if [ -n "$RECORDINGS_PATH" ]; then + sed -i "s|.*|file://${RECORDINGS_PATH}<\/recordings-path>|" $FILE + sed -i "s||file://${RECORDINGS_PATH}<\/recordings-path>|" $FILE + echo "Updated RECORDINGS_PATH " + + else + sed -i "s|.*|file://\${restcomm:home}/recordings<\/recordings-path>|" $FILE + sed -i "s||file://\${restcomm:home}/recordings<\/recordings-path>|" $FILE + fi + echo 'Configured Recordings path' +} + +## Description: Specify HTTP/S ports used. +#Needed when port offset is set. +configHypertextPort(){ + MSSFILE=$RESTCOMM_CONF/mss-sip-stack.properties + + #Check for Por Offset + local HTTP_PORT=$((HTTP_PORT + PORT_OFFSET)) + local HTTPS_PORT=$((HTTPS_PORT + PORT_OFFSET)) + + sed -e "s|org.mobicents.ha.javax.sip.LOCAL_HTTP_PORT=.*|org.mobicents.ha.javax.sip.LOCAL_HTTP_PORT=$HTTP_PORT|" \ + -e "s|org.mobicents.ha.javax.sip.LOCAL_SSL_PORT=.*|org.mobicents.ha.javax.sip.LOCAL_SSL_PORT=$HTTPS_PORT|" $MSSFILE > $MSSFILE.bak + mv $MSSFILE.bak $MSSFILE + echo "Configured HTTP ports" +} + +## Description: Other single configuration +#enable/disable SSLSNI (default:false) +otherRestCommConf(){ + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -e "s/.*<\/play-music-for-conference>/${PLAY_WAIT_MUSIC}<\/play-music-for-conference>/g;s//${PLAY_WAIT_MUSIC}<\/play-music-for-conference>/g" $FILE > $FILE.bak + mv $FILE.bak $FILE + + #Remove if is set in earlier run. + grep -q 'allowLegacyHelloMessages' $RESTCOMM_BIN/standalone.conf && sed -i -E "s/(.*)( -Dsun.security.ssl.allowLegacyHelloMessages=false -Djsse.enableSNIExtension=)(true|false)(.*)/\1\4/" $RESTCOMM_BIN/standalone.conf + + if [[ "$SSLSNI" == "false" || "$SSLSNI" == "FALSE" ]]; then + sed -i "s|-Djava.awt.headless=true|& -Dsun.security.ssl.allowLegacyHelloMessages=false -Djsse.enableSNIExtension=false|" $RESTCOMM_BIN/standalone.conf + else + sed -i "s|-Djava.awt.headless=true|& -Dsun.security.ssl.allowLegacyHelloMessages=false -Djsse.enableSNIExtension=true|" $RESTCOMM_BIN/standalone.conf + fi + + if [ -n "$HSQL_DIR" ]; then + echo "HSQL_DIR $HSQL_DIR" + FILEDB=$HSQL_DIR/restcomm.script + sed -i "s|.*|${HSQL_DIR}|" $FILE + if [ ! -f $FILEDB ]; then + mkdir -p $HSQL_DIR + cp $RESTCOMM_DEPLOY/WEB-INF/data/hsql/* $HSQL_DIR + fi + fi + + if [ -n "$USSDGATEWAYURI" ]; then + echo "USSD GATEWAY configuration" + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed -i "s|.*|$USSDGATEWAYURI|" $FILE + sed -i "s|.*|$USSDGATEWAYUSER|" $FILE + sed -i "s|.*|$USSDGATEWAYPASSWORD|" $FILE + + sed -i "s||$USSDGATEWAYURI|" $FILE + sed -i "s||$USSDGATEWAYUSER|" $FILE + sed -i "s||$USSDGATEWAYPASSWORD|" $FILE + fi + + echo "HTTP_RESPONSE_TIMEOUT $HTTP_RESPONSE_TIMEOUT" + sed -i"." "// { + N + N; + N; + N; + N; s|.*|$HTTP_RESPONSE_TIMEOUT| + }" $FILE + + sed -i"." "// { + N + N; + N; + N; + N; s||$HTTP_RESPONSE_TIMEOUT| + }" $FILE + + echo "CACHE_NO_WAV $CACHE_NO_WAV" + sed -i "s|.*|${CACHE_NO_WAV}|" $FILE + + echo "End Rest RestComm configuration" +} + +disableRVD() { + if [[ -f "$RVD_DEPLOY_PATH.deployed" || -f "$RVD_DEPLOY_PATH.dodeploy" ]]; then + rm -f "$RVD_DEPLOY_PATH.deployed" + rm -f "$RVD_DEPLOY_PATH.dodeploy" + echo "RVD undeployed (or not deployed at all)" + else + echo "RVD not deployed" + fi +} + +enableRVD() { + if [ -f "$RVD_DEPLOY_PATH.deployed" ]; then + echo "RVD already deployed" + else + touch "$RVD_DEPLOY_PATH".dodeploy + echo "RVD deployed" + fi +} + +confRVD(){ + if [[ "$RVD_UNDEPLOY" = true || "$RVD_UNDEPLOY" = True || "$RVD_UNDEPLOY" = TRUE ]]; then + disableRVD + else + enableRVD + echo "Configuring bundled RVD" + if [ -n "$RVD_LOCATION" ]; then + echo "RVD_LOCATION $RVD_LOCATION" + mkdir -p `echo $RVD_LOCATION` + sed -i "s|.*|${RVD_LOCATION}|" $RVD_DEPLOY_PATH/WEB-INF/rvd.xml + + COPYFLAG=$RVD_LOCATION/.demos_initialized + if [ -f "$COPYFLAG" ]; then + #Do nothing, we already copied the demo file to the new workspace + echo "RVD demo application are already copied" + else + echo "Will copy RVD demo applications to the new workspace $RVD_LOCATION" + cp -ar $RVD_DEPLOY_PATH/workspace/* $RVD_LOCATION + touch $COPYFLAG + fi + + fi + fi +} + +## Adds/removes / element based on $RVD_URL +## This version of confRcmlserver() will used xmlstarlet and will probably sed commands that rely on empty elements like instead of +#confRcmlserver(){ +# echo "Configuring ..." +# local RESTCOMM_XML=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml +# if [ -z "$RVD_URL" ]; then +# # remove / element altogether +# xmlstarlet ed -P -d "/restcomm/rcmlserver/base-url" "$RESTCOMM_XML" > "${RESTCOMM_XML}.bak" +# mv ${RESTCOMM_XML}.bak "$RESTCOMM_XML" +# else +# # remove existing element +# xmlstarlet ed -P -d /restcomm/rcmlserver/base-url "$RESTCOMM_XML" > "${RESTCOMM_XML}.bak" +# mv ${RESTCOMM_XML}.bak "$RESTCOMM_XML" +# # add it anew +# xmlstarlet ed -P -s /restcomm/rcmlserver -t elem -n base-url -v "$RVD_URL" "${RESTCOMM_XML}" > "${RESTCOMM_XML}.bak" +# mv "${RESTCOMM_XML}.bak" "$RESTCOMM_XML" +# fi +# echo " configured" +#} + +# Updates / according to $RVD_URL +# This version of confRcmlserver() used sed for backwards compatibility with existing sed commands in this +confRcmlserver() { + local RESTCOMM_XML=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + sed "//,/<\/rcmlserver>/ s|.*|${RVD_URL}|" "$RESTCOMM_XML" > "${RESTCOMM_XML}.bak" + mv ${RESTCOMM_XML}.bak "$RESTCOMM_XML" + echo "Configured . base-url set to '$RVD_URL'" +} + + +#Auto Configure RMS Networking, if MANUAL_SETUP=false. +configRMSNetworking() { + if [[ "$MANUAL_SETUP" == "false" || "$MANUAL_SETUP" == "FALSE" ]]; then + sed -i "s|BIND_ADDRESS=.*|BIND_ADDRESS=${BIND_ADDRESS}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|MGCP_ADDRESS=.*|MGCP_ADDRESS=${BIND_ADDRESS}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|NETWORK=.*|NETWORK=${BIND_NETWORK}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + sed -i "s|SUBNET=.*|SUBNET=${BIND_SUBNET_MASK}|" $RESTCOMM_BIN/restcomm/mediaserver.conf + fi +} + +configAsrDriver() { + if [ ! -z "$MG_ASR_DRIVERS" ] && [ ! -z "$MG_ASR_DRIVER_DEFAULT" ]; then + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + 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 --inplace -s "/restcomm/runtime-settings/mg-asr-drivers" -t elem -n "driver" -v "$driverName" \ + $FILE + done + fi +} + +## Description: DNS Provisioning Manager Configuration. +configDnsProvisioningManager() { + echo "Configure DnsProvisioningManager" + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/dns-provisioning" \ + -s "/restcomm/runtime-settings" -t elem -n dns-provisioning \ + -i "/restcomm/runtime-settings/dns-provisioning" -t attr -n class -v "$DNS_PROVISIONING_CLASS" \ + $FILE + + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/dns-provisioning" \ + -s "/restcomm/runtime-settings" -t elem -n dns-provisioning \ + -i "/restcomm/runtime-settings/dns-provisioning" -t attr -n enabled -v "$DNS_PROVISIONING_ENABLED" \ + $FILE + + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/dns-provisioning" \ + -s "/restcomm/runtime-settings" -t elem -n dns-provisioning \ + -i "/restcomm/runtime-settings/dns-provisioning" -t attr -n class -v "$DNS_PROVISIONING_CLASS" \ + $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning" -t attr -n "enabled" -v "$DNS_PROVISIONING_ENABLED" $FILE + + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/dns-provisioning/aws-route53" \ + -s "/restcomm/runtime-settings/dns-provisioning" -t elem -n aws-route53 $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "restcomm-a-record-value" -v "$DNS_PROVISIONING_AWS_ROUTE53_A_VALUE" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "restcomm-srv-record-value" -v "$DNS_PROVISIONING_AWS_ROUTE53_SRV_VALUE" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "access-key" -v "$DNS_PROVISIONING_AWS_ROUTE53_ACCESS_KEY" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "secret-key" -v "$DNS_PROVISIONING_AWS_ROUTE53_SECRET_KEY" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "region" -v "$DNS_PROVISIONING_AWS_ROUTE53_REGION" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "ttl" -v "$DNS_PROVISIONING_AWS_ROUTE53_TTL" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "hosted-zone-id" -v "$DNS_PROVISIONING_AWS_ROUTE53_HOSTED_ZONE_ID" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n "is-alias" -v "$DNS_PROVISIONING_AWS_ROUTE53_IS_ALIAS" $FILE + + + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/dns-provisioning/aws-route53/alias-target" \ + -s "/restcomm/runtime-settings/dns-provisioning/aws-route53" -t elem -n alias-target $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53/alias-target" -t elem -n "evaluate-target-health" -v "$DNS_PROVISIONING_AWS_ROUTE53_ALIAS_EVALUATE_TARGET_HEALTH" $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/dns-provisioning/aws-route53/alias-target" -t elem -n "hosted-zone-id" -v "$DNS_PROVISIONING_AWS_ROUTE53_ALIAS_HOSTED_ZONE_ID" $FILE + +} + +configConferenceTimeout(){ + echo "Configure conference timeout $CONFERENCE_TIMEOUT" + xmlstarlet ed --inplace -u "/restcomm/runtime-settings/conference-timeout" -v "$CONFERENCE_TIMEOUT" $FILE +} + +configSdrService(){ + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/sdr-service" $FILE + if [ -n "$SDR_SERVICE_CLASS" ]; then + echo "Configure Sdr service" + xmlstarlet ed --inplace -s "/restcomm/runtime-settings" -t elem -n sdr-service \ + -i "/restcomm/runtime-settings/sdr-service" -t attr -n class -v "$SDR_SERVICE_CLASS" \ + $FILE + if [ -n "$SDR_SERVICE_HTTP_URI" ]; then + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/sdr-service" -t elem -n http-uri -v "$SDR_SERVICE_HTTP_URI" $FILE + fi + if [ -n "$SDR_SERVICE_AMQP_URI" ]; then + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/sdr-service" -t elem -n amqp-uri -v "$SDR_SERVICE_AMQP_URI" $FILE + fi + fi +} + +# MAIN +echo 'Configuring RestComm...' +configRCJavaOpts +configDARSProperties +configRestcomm "$PUBLIC_IP" +#configVoipInnovations "$VI_LOGIN" "$VI_PASSWORD" "$VI_ENDPOINT" + +if [ "$ACTIVATE_LB" == "true" ] || [ "$ACTIVATE_LB" == "TRUE" ]; then + HOSTFORDID=$LBHOST +else + HOSTFORDID=$PUBLIC_IP + + #Check for port offset. + DID_URIPORT=$((DID_URIPORT + PORT_OFFSET)) +fi + +if [ -z "$MS_ADDRESS" ]; then + MS_ADDRESS=$BIND_ADDRESS +fi + +configDidProvisionManager "$DID_LOGIN" "$DID_PASSWORD" "$DID_ENDPOINT" "$DID_SITEID" "$HOSTFORDID" "$DID_ACCOUNTID" "$SMPP_SYSTEM_TYPE" "$DID_URIPORT" +configFaxService "$INTERFAX_USER" "$INTERFAX_PASSWORD" +configSmsAggregator "$SMS_OUTBOUND_PROXY" "$SMS_PREFIX" +configSpeechRecognizer "$ISPEECH_KEY" +configSpeechSynthesizers +configTelestaxProxy "$ACTIVE_PROXY" "$TP_LOGIN" "$TP_PASSWORD" "$INSTANCE_ID" "$PROXY_IP" "$SITE_ID" +configMediaServerManager "$BIND_ADDRESS" "$MS_ADDRESS" "$MEDIASERVER_EXTERNAL_ADDRESS" +configSMPPAccount "$SMPP_ACTIVATE" "$SMPP_SYSTEM_ID" "$SMPP_PASSWORD" "$SMPP_SYSTEM_TYPE" "$SMPP_PEER_IP" "$SMPP_PEER_PORT" "$SMPP_SOURCE_MAP" "$SMPP_DEST_MAP" +configRestCommURIs +updateRecordingsPath +configHypertextPort +configOutboundProxy +configPushNotificationServer +otherRestCommConf +confRcmlserver +confRVD +configRMSNetworking +configAsrDriver +configDnsProvisioningManager +configConferenceTimeout +configSdrService +echo 'Configured RestComm!' diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd-logging.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd-logging.sh new file mode 100755 index 0000000000..5aed5b9025 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd-logging.sh @@ -0,0 +1,190 @@ +#!/bin/bash +## +## Logging configuration for RVD +## +## standalone-sip.xml is updated with RVD handler and loggers configuration. By default, if the respective +## configuration is missing it is added. Otherwise nothing happens. If the logging LEVEL is specified in the +## command line loggers are updated/created accordingly. +## +## usage: +## +## ./config-rvd-logging.sh - adds handler and logger (INFO) elements if missing +## ./config-rvd-logging.sh DEBUG - creates or updates loggers by setting level to DEBUG +## ./config-rvd-logging.sh DEBUG FILE - creates or updates loggers (DEBUG) but also configures them to use the 'FILE' periodic handler (main restcomm log) +## +## environment: +## +## requires RESTCOMM_HOME env variable to be set +## +## Author: otsakir@gmail.com - Orestis Tsakiridis + +# Default values +STANDALONE_SIP=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml +LOG_FILE="rvd/rvd.log"; # this is relative to "jboss.server.log.dir" +RVD_LOG_LEVEL=INFO # logging level that will be used if handlers/loggers are missing +LOGGING_HANDLER=RVD # the handler to be used for RVD logging. Set this to 'FILE' to redirect all messages to the main restcomm log (server.log) + +# Variables +XML_UPDATED=false # flag to format xml file only if updated +OVERRIDE=false + +error(){ + echo "error parsing standalone-sip.xml" + exit 1 +} + +createHandler(){ + + # create the RVD handler if it is missing + xmlstarlet sel -Q -N logns=urn:jboss:domain:logging:1.2 -t -m "//logns:periodic-rotating-file-handler[@name='RVD']" -o "found" $STANDALONE_SIP + result=$? + if [ "$result" -eq 1 ]; then + echo "adding RVD handler" + xmlstarlet ed -P -N logns=urn:jboss:domain:logging:1.2 -d "//logns:periodic-rotating-file-handler[@name='RVD']" -s "//logns:subsystem" -t elem -n periodic-rotating-file-handler_TMP -v "" \ + -i //periodic-rotating-file-handler_TMP -t attr -n name -v RVD \ + -i //periodic-rotating-file-handler_TMP -t attr -n autoflush -v true \ + -s //periodic-rotating-file-handler_TMP -t elem -n formatter_TMP -v "" \ + -s //formatter_TMP -t elem -n pattern-formatter_TMP -v "" \ + -i //pattern-formatter_TMP -t attr -n pattern -v "%d{MMdd HH:mm:ss,SSS X} %p (%t) %m %n" \ + -s //periodic-rotating-file-handler_TMP -t elem -n file_TMP -v "" \ + -i //file_TMP -t attr -n relative-to -v "jboss.server.log.dir" \ + -i //file_TMP -t attr -n path -v "rvd/rvd.log" \ + -s //periodic-rotating-file-handler_TMP -t elem -n suffix_TMP -v "" \ + -s //suffix_TMP -t attr -n value -v ".yyyy-MM-dd" \ + -s //periodic-rotating-file-handler_TMP -t elem -n append_TMP -v "" \ + -s //append_TMP -t attr -n value -v true \ + -r //periodic-rotating-file-handler_TMP -v periodic-rotating-file-handler \ + -r //formatter_TMP -v formatter \ + -r //pattern-formatter_TMP -v pattern-formatter \ + -r //file_TMP -v file \ + -r //suffix_TMP -v suffix \ + -r //append_TMP -v append \ + $STANDALONE_SIP > ${STANDALONE_SIP}_tmp + mv ${STANDALONE_SIP}_tmp $STANDALONE_SIP + XML_UPDATED=true + else + if [ "$result" -eq 3 ]; + then + error + fi + fi + +} + +createLoggers(){ + + # create RVD local logger if it is missing + xmlstarlet sel -Q -N logns=urn:jboss:domain:logging:1.2 -t -m "//logns:logger[@category='org.restcomm.connect.rvd.LOCAL']" -o "found" $STANDALONE_SIP + result=$? + if [ "$result" -eq 1 -o \( "$result" = 0 -a "$OVERRIDE" = true \) ]; then + echo "adding RVD local logger - $RVD_LOG_LEVEL/$LOGGING_HANDLER handler" + xmlstarlet ed -P -N logns=urn:jboss:domain:logging:1.2 -d "//logns:logger[@category='org.restcomm.connect.rvd.LOCAL']" \ + -s "//logns:subsystem" -t elem -n logger_TMP -v "" \ + -i //logger_TMP -t attr -n category -v "org.restcomm.connect.rvd.LOCAL" \ + -s //logger_TMP -t elem -n level_TMP -v "" \ + -i //level_TMP -t attr -n name -v "$RVD_LOG_LEVEL" \ + -s //logger_TMP -t elem -n handlers_TMP -v "" \ + -s //handlers_TMP -t elem -n handler_TMP -v "" \ + -s //handler_TMP -t attr -n name -v "$LOGGING_HANDLER" \ + -r //logger_TMP -v logger \ + -r //level_TMP -v level \ + -r //handlers_TMP -v handlers \ + -r //handler_TMP -v handler \ + $STANDALONE_SIP > ${STANDALONE_SIP}_tmp + mv ${STANDALONE_SIP}_tmp $STANDALONE_SIP + XML_UPDATED=true + else + if [ "$result" -eq 3 ]; + then + error + fi + fi + + # create RVD global logger if it is missing + xmlstarlet sel -Q -N logns=urn:jboss:domain:logging:1.2 -t -m "//logns:logger[@category='org.restcomm.connect.rvd.GLOBAL']" -o "found" $STANDALONE_SIP + result=$? + if [ "$result" -eq 1 -o \( "$result" = 0 -a "$OVERRIDE" = true \) ]; then + echo "adding RVD global logger - $RVD_LOG_LEVEL/$LOGGING_HANDLER handler" + xmlstarlet ed -P -N logns=urn:jboss:domain:logging:1.2 -d "//logns:logger[@category='org.restcomm.connect.rvd.GLOBAL']" \ + -s "//logns:subsystem" -t elem -n logger_TMP -v "" \ + -i //logger_TMP -t attr -n category -v "org.restcomm.connect.rvd.GLOBAL" \ + -s //logger_TMP -t elem -n level_TMP -v "" \ + -i //level_TMP -t attr -n name -v "$RVD_LOG_LEVEL" \ + -s //logger_TMP -t elem -n handlers_TMP -v "" \ + -s //handlers_TMP -t elem -n handler_TMP -v "" \ + -s //handler_TMP -t attr -n name -v "$LOGGING_HANDLER" \ + -r //logger_TMP -v logger \ + -r //level_TMP -v level \ + -r //handlers_TMP -v handlers \ + -r //handler_TMP -v handler \ + $STANDALONE_SIP > ${STANDALONE_SIP}_tmp + mv ${STANDALONE_SIP}_tmp $STANDALONE_SIP + XML_UPDATED=true + else + if [ "$result" -eq 3 ]; + then + error + fi + fi +} + +formatXml(){ + tmpfile=$(mktemp -t rvdconfigXXX) + xmlstarlet fo "$STANDALONE_SIP" > "$tmpfile" + mv "$tmpfile" "$STANDALONE_SIP" +} + +# MAIN + +if [ -z "$RESTCOMM_HOME" ] +then + echo "RESTCOMM_HOME env variable not set" + exit 1 +fi + +echo "Configuring RVD logging" + +# if no (level) argument is given, create default loggers only if they are missing +if [ -z $1 ] +then + # OVERRIDE is false + createHandler + createLoggers +else + case "$1" in + FATAL|ERROR|WARN|INFO|DEBUG|TRACE|ALL|OFF) + # specify logging handler to be used - RVD|FILE) + if [ -z "$2" ] + then + LOGGING_HANDLER=RVD + else + case "$2" in + RVD|FILE) + LOGGING_HANDLER=$2 + ;; + *) + echo "invalid arguments: handler should be one of RVD|FILE" + exit 1 + ;; + esac + fi + RVD_LOG_LEVEL=$1 + OVERRIDE=true + createHandler + createLoggers + ;; + *) + echo "invalid arguments: level should be one of FATAL|ERROR|WARN|INFO|DEBUG|TRACE|ALL|OFF" + exit 1 + ;; + esac + +fi + +# format output if any update happened +if [ "$XML_UPDATED" = true ] +then + formatXml + echo "$STANDALONE_SIP updated" +fi + 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 new file mode 100755 index 0000000000..2497dc9a13 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd.sh @@ -0,0 +1,92 @@ +#!/bin/bash +## +## Configures rvd.xml based on global configuration options in restcomm.conf and advanced.conf. +## +## usage: +## +## ./config-rvd-logging.sh - adds handler and logger (INFO) elements if missing +## ./config-rvd-logging.sh DEBUG - creates or updates loggers by setting level to DEBUG +## ./config-rvd-logging.sh DEBUG FILE - creates or updates loggers (DEBUG) but also configures them to use the 'FILE' periodic handler (main restcomm log) +## +## requirements: +## +## RESTCOMM_HOME env variable to be set +## rvd.xml should be in place (under $RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war) +## +## Author: otsakir@gmail.com - Orestis Tsakiridis + +# Variables +RVD_ROOT=$RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war +RVD_XML_FILE=$RVD_ROOT/WEB-INF/rvd.xml + +updateVideoSupport() { + matchesCount=`xmlstarlet sel -t -v "count(/rvd/videoSupport)" "$RVD_XML_FILE"` + if [ $matchesCount -ge 1 ]; then + xmlstarlet ed -P -u "/rvd/videoSupport" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + else + xmlstarlet ed -P -s "/rvd" -t elem -n "videoSupport" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + fi +} + +updateMaxMediaFileSize() { + matchesCount=`xmlstarlet sel -t -v "count(/rvd/maxMediaFileSize)" "$RVD_XML_FILE"` + if [ $matchesCount -ge 1 ]; then + xmlstarlet ed -P -u "/rvd/maxMediaFileSize" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + else + xmlstarlet ed -P -s "/rvd" -t elem -n "maxMediaFileSize" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + fi +} + +# $1 is RVD_HTTP_TIMEOUT +updateHttpTimeout() { + if [ -z $1 ]; then + xmlstarlet ed -P -d "/rvd/defaultHttpTimeout" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + echo "disabled defaultHttpTimeout option"; + else + matchesCount=`xmlstarlet sel -t -v "count(/rvd/defaultHttpTimeout)" "$RVD_XML_FILE"` + if [ $matchesCount -ge 1 ]; then + xmlstarlet ed -P -u "/rvd/defaultHttpTimeout" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + else + xmlstarlet ed -P -s "/rvd" -t elem -n "defaultHttpTimeout" -v "$1" "$RVD_XML_FILE" > ${RVD_XML_FILE}_tmp + mv ${RVD_XML_FILE}_tmp ${RVD_XML_FILE} + fi + echo "set defaultHttpTimeout to $1" + fi +} + +# MAIN + +if [[ "$RVD_UNDEPLOY" = true || "$RVD_UNDEPLOY" = TRUE || "$RVD_UNDEPLOY" = True ]]; then + echo "Skipping RVD configuration since it's not deployed" +else + if [ -z "$RESTCOMM_HOME" ] + then + echo "RESTCOMM_HOME env variable not set. Aborting." + exit 1 + fi + if [ ! -f "$RVD_XML_FILE" ] + then + echo "rvd.xml not found. Aborting." + return + fi + + echo "Configuring RVD" + + if [[ "$RVD_VIDEO_SUPPORT" = true || "$RVD_VIDEO_SUPPORT" = TRUE || "$RVD_VIDEO_SUPPORT" = True ]] ; then + updateVideoSupport true + else + updateVideoSupport false + fi + updateMaxMediaFileSize "$RVD_MAX_MEDIA_FILE_SIZE" + + updateHttpTimeout "$RVD_HTTP_TIMEOUT" + + + echo "Updated rvd.xml" +fi \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-sip-connectors.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-sip-connectors.sh new file mode 100755 index 0000000000..b0e86b523e --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-sip-connectors.sh @@ -0,0 +1,160 @@ +#!/bin/bash +## Description: Configures SIP connectors +## Author : Henrique Rosa (henrique.rosa@telestax.com) +## Author : Pavel Slegr (pavel.slegr@telestax.com) + +## Description: Configures the connectors for RestComm & configures Proxy if enabled +## Parameters : 1.Public IP +configConnectors() { + FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml + static_address="$1" + + #delete additional connectors if any added to erlier run of the script. + if grep -q "" $FILE + then + echo "Additional Connectors Created earlier, going to delete the connectors" + sed '//,//d' $FILE > $FILE.bak + mv $FILE.bak $FILE + else + echo "Additional Connectors not Created earlier" + fi + + #IF LB activated. (Algorithm "use-load-balancer" used). + if [ "$ACTIVATE_LB" == "true" ] || [ "$ACTIVATE_LB" == "TRUE" ]; then + if [ -z "$LB_INTERNAL_IP" ]; then + LB_INTERNAL_IP=$LB_PUBLIC_IP + fi + sed -e "s|path-name=\"org.mobicents.ext\" \(app-dispatcher-class=.*\)|path-name=\"org.mobicents.ha.balancing.only\" \1|" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + $FILE > $FILE.bak + + else + + #Check for Por Offset + local SIP_PORT_UDP=$((SIP_PORT_UDP + PORT_OFFSET)) + local SIP_PORT_TCP=$((SIP_PORT_TCP + PORT_OFFSET)) + local SIP_PORT_TLS=$((SIP_PORT_TLS + PORT_OFFSET)) + local SIP_PORT_WS=$((SIP_PORT_WS + PORT_OFFSET)) + local SIP_PORT_WSS=$((SIP_PORT_WSS + PORT_OFFSET)) + + sed -e "s|path-name=\".*\" \(app-dispatcher-class=.*\)|path-name=\"org.mobicents.ext\" \1|" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + $FILE > $FILE.bak + fi + mv $FILE.bak $FILE + echo 'Configured SIP Connectors and Bindings' + + + #Enable SipServlet statistics + grep -q 'gather-statistics' $FILE || sed -i "s|congestion-control-interval=\".*\"|& gather-statistics=\"true\"|" $FILE + echo "Configured gather-statistics" +} + +#Socket Binding configuration for standalone-sip.xml +configSocketbinding() { +FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml + + #delete additional bindings if any added to erlier run of the script. + if grep -q "" $FILE + then + echo "Additional Bindings Created earlier, going to delete the old bindings" + sed '//,//d' $FILE > $FILE.bak + mv $FILE.bak $FILE + else + echo "Additional Bindings not Created earlier" + fi + + #check for port offset + sed -i "s|\port-offset=\".*\"|port-offset=\"${PORT_OFFSET}\"|" $FILE + + sed -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + -e "s|||" \ + $FILE > $FILE.bak + mv $FILE.bak $FILE +} + +setMoreConnectors(){ +flag1=false +flag2=false + for i in $( set -o posix ; set | grep ^ADDITIONAL_CONNECTOR_ | sort -rn ); do + connector=$(echo ${i} | cut -d = -f2 | cut -d _ -f2 | cut -d : -f1) + port=$(echo ${i} | cut -d = -f2 | cut -d _ -f2 | cut -d : -f2) + if [ "$flag1" = false ] ; then + setInitialSign + flag1=true + fi + addConector $connector $port + addSocketBinding $connector $port + echo "Configuring log level for: $connector -> $port" + flag2=true + done + + if [ "$flag2" = true ] ; then + setFinalSign + fi +} + +addConector(){ +FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml +connector=$1 +port=$2 + + #check for port offset at the new connectors. + local port=$((port + PORT_OFFSET)) + grep -q "connector name=\"${connector}\"" $FILE || sed -e "/path-name=\"org.mobicents.ext\"/a\ + " $FILE > $FILE.bak + + mv $FILE.bak $FILE + echo 'Configured additional SIP Connectors and Bindings' +} + +addSocketBinding(){ +FILE=$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml +connector=$1 +port=$2 + + grep -q "socket-binding name=\"${connector}\"" $FILE || sed "/name=\"management-https\"/a " $FILE > $FILE.bak + mv $FILE.bak $FILE +} + +setInitialSign(){ + sed -e "/path-name=\"org.mobicents.ext\"/a\ + " $FILE > $FILE.bak + mv $FILE.bak $FILE + + sed "/name=\"management-https\"/a " $FILE > $FILE.bak + mv $FILE.bak $FILE +} + +setFinalSign(){ + sed -e "/path-name=\"org.mobicents.ext\"/a\ + " $FILE > $FILE.bak + + mv $FILE.bak $FILE + sed "/name=\"management-https\"/a " $FILE > $FILE.bak + mv $FILE.bak $FILE +} + +#MAIN +echo 'Configuring Application Server...' +configSocketbinding +configConnectors "$PUBLIC_IP" +if [ "$ACTIVATE_LB" == "true" ] || [ "$ACTIVATE_LB" == "TRUE" ]; then + echo "can not set additional connectors under LB." +else + setMoreConnectors +fi +echo 'Finished configuring Application Server!' diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-utensil.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-utensil.sh new file mode 100755 index 0000000000..5816553435 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-utensil.sh @@ -0,0 +1,155 @@ +#!/bin/bash +## +## Description: Configures RestComm +## Author: Henrique Rosa (henrique.rosa@telestax.com) +## Author: Pavel Slegr (pavel.slegr@telestax.com) +## Authos: Lefteris Banos (eleftherios.banos@telestax.com) + +# VARIABLES +RESTCOMM_BIN=$RESTCOMM_HOME/bin +RESTCOMM_DEPLOY=$RESTCOMM_HOME/standalone/deployments/restcomm.war + +configS3Bucket() { + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + + if [[ "$ACTIVATE_S3_BUCKET" == "true" || "$ACTIVATE_S3_BUCKET" == "TRUE" ]]; then + echo "S3_BUCKET_NAME $S3_BUCKET_NAME S3_ACCESS_KEY $S3_ACCESS_KEY S3_SECURITY_KEY $S3_SECURITY_KEY" + sed -e "// { + N; s|.*|true| + N; s|.*|${S3_BUCKET_NAME}| + N; s|.*|${S3_FOLDER_NAME}| + N; s|.*|${S3_ACCESS_KEY}| + N; s|.*|${S3_SECURITY_KEY}| + }" $FILE > $FILE.bak; + mv $FILE.bak $FILE + + if [ -n "$S3_BUCKET_REGION" ]; then + echo "S3_BUCKET_REGION $S3_BUCKET_REGION" + sed -e "s|.*|${S3_BUCKET_REGION}|" $FILE > $FILE.bak; + mv $FILE.bak $FILE + fi + else + sed -e "// { + N; s|.*|false| + N; s|.*|| + N; s|.*|| + N; s|.*|| + }" $FILE > $FILE.bak; + mv $FILE.bak $FILE + fi +} + +initUserPassword(){ + SQL_FILE=$RESTCOMM_DEPLOY/WEB-INF/data/hsql/restcomm.script + if [ -n "$INITIAL_ADMIN_USER" ]; then + # change admin user + if grep -q "uninitialized" $SQL_FILE; then + echo "Update Admin user" + sed -i "s/administrator@company.com/${INITIAL_ADMIN_USER}/g" $SQL_FILE + else + echo "Adminitrator User Already changed" + fi + fi + + if [ -n "$INITIAL_ADMIN_PASSWORD" ]; then + # change admin password + if grep -q "uninitialized" $SQL_FILE; then + PASSWORD_ENCRYPTED=`echo -n "${INITIAL_ADMIN_PASSWORD}" | md5sum |cut -d " " -f1` + #echo "Update password to ${INITIAL_ADMIN_PASSWORD}($PASSWORD_ENCRYPTED)" + sed -i "s/uninitialized/active/g" $SQL_FILE + sed -i "s/77f8c12cc7b8f8423e5c38b035249166/$PASSWORD_ENCRYPTED/g" $SQL_FILE + sed -i "s/2012-04-24 00:00:00.000000000/`echo "$(date +'%Y-%m-%d %H:%M:%S.%N')"`/" $SQL_FILE + sed -i "s/2012-04-24 00:00:00.000000000/`echo "$(date +'%Y-%m-%d %H:%M:%S.%N')"`/" $SQL_FILE + else + echo "Adminitrator Password Already changed" + fi + fi +} + +configSMTP(){ + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + if [[ -z $SMTP_USER || -z $SMTP_PASSWORD || -z $SMTP_HOST ]]; then + echo 'one or more variables are undefined' + echo 'Not possible to continue with SMTP configuration' + + else + echo "SMTP_USER $SMTP_USER SMTP_PASSWORD $SMTP_PASSWORD SMTP_HOST $SMTP_HOST" + sed -i "// { + N; s|.*|${SMTP_HOST}| + N; s|.*|${SMTP_USER}| + N; s|.*|${SMTP_PASSWORD}| + N; s|.*|${SMTP_PORT}| + }" $FILE + + sed -i "// { + N; s|.*|${SMTP_HOST}| + N; s|.*|${SMTP_USER}| + N; s|.*|${SMTP_PASSWORD}| + N; s|.*|${SMTP_PORT}| + }" $FILE + fi +} + +configMonitoring(){ + if [ -z ${GRAYLOG_SERVER} ]; then + echo "Graylog Monitoring is not configured"; + crontab -l 2>/dev/null > mycron + crontab -l | grep -q 'HDmonitor' && sed -i '/HDmonitor/d' mycron + crontab -l | grep -q 'RMSJVMonitor' && sed -i '/RMSJVMonitor/d' mycron + crontab -l | grep -q 'RCJVMonitor' && sed -i '/RCJVMonitor/d' mycron + crontab -l | grep -q 'SERVERAMonitor' && sed -i '/SERVERAMonitor/d' mycron + #install new cron file + crontab mycron + rm mycron + + else + echo "GRAYLOG_SERVER is: $GRAYLOG_SERVER"; + + #write out current crontab RMSJVMonitor + crontab -l 2>/dev/null > mycron + + #echo new cron into cron file + crontab -l | grep -q 'MAILTO=""' && echo 'entry exists' || echo "MAILTO=\"\"" >> mycron + if [[ "$HD_MONITOR" == "false" || "$HD_MONITOR" == "FALSE" ]]; then + sed -i '/HDmonitor/d' mycron + echo "HD_MONITOR: $HD_MONITOR" + else + crontab -l | grep -q 'Graylog_Monitoring.sh HDmonitor' && echo 'entry exists' || echo "*/30 * * * * $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh HDmonitor" >> mycron; + fi + + if [[ "$RMSJVM_MONITOR" == "false" || "$RMSJVM_MONITOR" == "FALSE" ]]; then + sed -i '/RMSJVMonitor/d' mycron + echo "RMSJVM_MONITOR: $RMSJVM_MONITOR"; + else + crontab -l | grep -q 'Graylog_Monitoring.sh RMSJVMonitor' && echo 'entry exists' || echo "* * * * * $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh RMSJVMonitor" >> mycron; + fi + + if [[ "$RCJVM_MONITOR" == "false" || "$RCJVM_MONITOR" == "FALSE" ]]; then + sed -i '/RCJVMonitor/d' mycron + echo "RCJVM_MONITOR: $RCJVM_MONITOR"; + else + crontab -l | grep -q 'Graylog_Monitoring.sh RCJVMonitor' && echo 'entry exists' || echo "* * * * * $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh RCJVMonitor" >> mycron; + fi + + if [[ "$RAM_MONITOR" == "false" || "$RAM_MONITOR" == "FALSE" ]]; then + sed -i '/SERVERAMonitor/d' mycron + echo "RAM_MONITOR: $RAM_MONITOR"; + else + crontab -l | grep -q 'Graylog_Monitoring.sh SERVERAMonitor' && echo 'entry exists' || echo "* * * * * $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh SERVERAMonitor" >> mycron; + fi + + #install new cron file + crontab mycron + rm mycron + + #set Server Label + sed -i "s|SERVERLABEL=.*|SERVERLABEL=\"${SERVERLABEL}\"|" $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh; + sed -i "s|GRAYLOG_SERVER=.*|GRAYLOG_SERVER=\"${GRAYLOG_SERVER}\"|" $RESTCOMM_BIN/restcomm/monitoring/Graylog_Monitoring.sh; + fi +} + +# MAIN +configS3Bucket +initUserPassword +configSMTP +configMonitoring diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh new file mode 100755 index 0000000000..454c5dca4d --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfigure.sh @@ -0,0 +1,35 @@ +#! /bin/bash + +## Description: Executes all RestComm configuration scripts for a given version. +## Author : Henrique Rosa (henrique.rosa@telestax.com) + +autoconfigure() { + local BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) + + ## We want this file to be executed last since its contains xmlstarlet based config script + ## https://telestax.atlassian.net/browse/RESTCOMM-1140 + local LAST_FILE_TO_BE_EXECUTED=$BASEDIR/autoconfig.d/config-restcomm.sh + + # load configuration values + #source $BASEDIR/restcomm.conf + echo '' + echo 'RestComm automatic configuration started:' + echo "LAST_FILE_TO_BE_EXECUTED is: $LAST_FILE_TO_BE_EXECUTED" + for f in $BASEDIR/autoconfig.d/*.sh; do + echo "Executing configuration file $f..." + if [ "$f" != "$LAST_FILE_TO_BE_EXECUTED" ]; then + source $f + echo "Finished executing configuration file $f!" + echo '' + fi + done + + source $LAST_FILE_TO_BE_EXECUTED + echo "Finished executing configuration file $LAST_FILE_TO_BE_EXECUTED!" + echo '' + + echo 'RestComm automatic configuration finished!' + echo '' +} + +autoconfigure \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/collect_jmap.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/collect_jmap.sh new file mode 100755 index 0000000000..58b00dc67b --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/collect_jmap.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +## +## Descript+ion: Script that collects all necessary system logs and data. +## Author : Lefteris Banos +## Author : George Vagenas +# + +##Global Parameters +DATE=$(date +%F_%H_%M) +DIR_NAME=restcomm_$DATE +BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +JMAP_DIR=$BASEDIR/$DIR_NAME + +JMAP="true" +DTAR="true" + +## +## FUNCTIONS +## +getPID(){ + RESTCOMM_PID=" " + RMS_PID="" + + RESTCOMM_PID=$(jps | grep jboss-modules.jar | cut -d " " -f 1) + + while read -r line + do + if ps -ef | grep $line | grep -q mediaserver + then + RMS_PID=$line + fi + done < <(jps | grep Main | cut -d " " -f 1) + +} + +restcomm_jmap(){ +if [[ -z "$RESTCOMM_PID" ]]; then + getPID +fi + +if [[ -z "$RESTCOMM_PID" ]]; then + echo "Please make sure that RestComm is running..." + else + echo "****************************************************************" > $JMAP_DIR/restcomm_mem + echo "GC Histogram before GC.run" >> $JMAP_DIR/restcomm_mem + echo "****************************************************************" >> $JMAP_DIR/restcomm_mem + jcmd $RESTCOMM_PID GC.class_histogram | grep org.restcomm.connect >> $JMAP_DIR/restcomm_mem + + jcmd $RESTCOMM_PID GC.run + sleep 5 + + echo "****************************************************************" >> $JMAP_DIR/restcomm_mem + echo "GC Histogram after GC.run" >> $JMAP_DIR/restcomm_mem + echo "****************************************************************" >> $JMAP_DIR/restcomm_mem + jcmd $RESTCOMM_PID GC.class_histogram | grep org.restcomm.connect >> $JMAP_DIR/restcomm_mem + + echo "****************************************************************" >> $JMAP_DIR/restcomm_mem + echo "JVMTop" >> $JMAP_DIR/restcomm_mem + echo "****************************************************************" >> $JMAP_DIR/restcomm_mem + $BASEDIR/jvmtop.sh -n 1 >> $JMAP_DIR/restcomm_mem + + jmap -dump:live,format=b,file=restcomm_jmap_$DATE.bin $RESTCOMM_PID + mv restcomm_jmap_$DATE.bin $JMAP_DIR + fi + +} + +rms_jmap(){ +if [[ -z "$RMS_PID" ]]; then + getPID +fi + +if [[ -z "$RMS_PID" ]]; then + echo "Please make sure that Mediaserver is running..." + else + jcmd $RMS_PID GC.run + sleep 2 + jmap -dump:live,format=b,file=rms_jmap_$DATE.bin $RMS_PID + mv rms_jmap_$DATE.bin $JMAP_DIR + fi +} + +make_tar() { + if [ -d "$JMAP_DIR" ]; then + echo TAR_FILE : $JMAP_DIR.tar.gz + tar -zcf $JMAP_DIR.tar.gz -C $JMAP_DIR . 3>&1 1>&2 2>&3 + rm -rf $JMAP_DIR + return 0 + fi + exit 1 +} + +mkdir $JMAP_DIR +restcomm_jmap +rms_jmap +make_tar diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/gsed_macos.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/gsed_macos.sh new file mode 100755 index 0000000000..2c934ea154 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/gsed_macos.sh @@ -0,0 +1,6 @@ +#!/bin/bash +## Description: Change 'sed' to 'gsed' for MacOS users in order for the autoconfig scripts to work properly +## Prerequisites: Install gnu-sed using homebrew (brew install gnu-sed) +## Author: George Vagenas +gsed -i 's/sed/gsed/g' ./*.sh +gsed -i 's/sed/gsed/g' ./autoconfig.d/*.sh diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.jar b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.jar new file mode 100644 index 0000000000..eb5d7f8460 Binary files /dev/null and b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.jar differ diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.sh new file mode 100755 index 0000000000..32aa5305b2 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/jvmtop.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# jvmtop - java monitoring for the command-line +# launch script +# +# author: Markus Kolb +# + +DIR=`cd "\`dirname "$0"\`" && pwd` + +if [ -z "$JAVA_HOME" ] ; then + JAVA_HOME=`readlink -f \`which java 2>/dev/null\` 2>/dev/null | \ + sed 's/\/bin\/java//'` +fi + +TOOLSJAR="$JAVA_HOME/../lib/tools.jar" + +if [ ! -f "$TOOLSJAR" ] ; then + echo "$JAVA_HOME seems to be no JDK!" >&2 + exit 1 +fi + +"$JAVA_HOME"/bin/java $JAVA_OPTS -cp "$DIR/jvmtop.jar:$TOOLSJAR" \ +com.jvmtop.JvmTop "$@" +exit $? diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/logs_collect.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/logs_collect.sh new file mode 100755 index 0000000000..f253f176be --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/logs_collect.sh @@ -0,0 +1,206 @@ +#!/bin/bash +## +## Descript+ion: Script that collects all necessary system logs and data. +## Author : Lefteris Banos +# +DATE=$(date +%F_%H_%M) +DIR_NAME=restcomm_$DATE +RESTCOMM_CORE_FILE=server.log +MEDIASERVER_FILE=server.log +SYSLOGS_DIR=/var/log +BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +RESTCOMM_LOG_BASE=$(cd $BASEDIR/../../ && pwd) +RESTCOMM_CORE_LOG=$RESTCOMM_LOG_BASE/standalone/log +RVD_LOG=$RESTCOMM_LOG_BASE/standalone/log/rvd +RVD_LOG_FILE=rvd.log +MMS_LOGS=$RESTCOMM_LOG_BASE/mediaserver/log +LOGS_DIR_ZIP=$BASEDIR/$DIR_NAME + +restcomm_logs () { + if [ -f $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE ]; then + cp $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE $LOGS_DIR_ZIP/restcomm_server.log + fi +} +restcomm_logs_bytime () { + if [ -f $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE ]; then + IN=$1 + IFS="," + arr=($IN) + unset IFS + FROM=`grep -n "^${arr[0]}" $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE |cut -f1 -d: | tail -1` + TO=`grep -n "^${arr[1]}" $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE |cut -f1 -d: | tail -1` + awk 'NR=="'"$FROM"'", NR=="'"$TO"'"; NR=="'"$TO"'" {print; exit}' $RESTCOMM_CORE_LOG/$RESTCOMM_CORE_FILE > $LOGS_DIR_ZIP/RestCommlinesTime.log + fi +} +rvd_logs () { + if [ -f $RVD_LOG/$RVD_LOG_FILE ]; then + cp $RVD_LOG/$RVD_LOG_FILE $LOGS_DIR_ZIP/rvd_server.log + fi +} +mediaserver_logs () { + if [ -f $MMS_LOGS/$MEDIASERVER_FILE ]; then + cp $MMS_LOGS/$MEDIASERVER_FILE $LOGS_DIR_ZIP/mms_server.log + fi +} +system_logs () { + if [ -f $SYSLOGS_DIR/messages ]; then + cp $SYSLOGS_DIR/messages $LOGS_DIR_ZIP/ + fi + if [ -f $SYSLOGS_DIR/syslog ]; then + cp $SYSLOGS_DIR/syslog $LOGS_DIR_ZIP/ + fi +} +JVM_perfo_stats () { + if [ -n "$RESTCOMM_PID" ]; then + jstack -l $RESTCOMM_PID > $LOGS_DIR_ZIP/restcomm_jstack_trace_$DATE + fi + if [ -n "$RMS_PID" ]; then + jstack -l $RMS_PID > $LOGS_DIR_ZIP/mms_jstack_trace_$DATE + fi +} +system_usage_info () { + echo "---top:" > $LOGS_DIR_ZIP/usage_stats_$DATE + echo CPU\(s\): `top -b -n1 | grep "Cpu(s)" | awk '{print $2" : " $4}'` >> $LOGS_DIR_ZIP/usage_stats_$DATE + echo >> $LOGS_DIR_ZIP/usage_stats_$DATE + top -b -n1 | grep Mem >> $LOGS_DIR_ZIP/usage_stats_$DATE + echo "---free:" >> $LOGS_DIR_ZIP/usage_stats_$DATE + free >> $LOGS_DIR_ZIP/usage_stats_$DATE + echo "---df:" >> $LOGS_DIR_ZIP/usage_stats_$DATE + df -h >> $LOGS_DIR_ZIP/usage_stats_$DATE + ps aux > $LOGS_DIR_ZIP/top_$DATE +} +jvm_process_info () { + if [ -n "$RESTCOMM_PID" ]; then + echo "----------------------- restcomm ---------------------------" > $LOGS_DIR_ZIP/jvm_process_$DATE + echo "--------New Generation Heap-------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gcnew $RESTCOMM_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "--------New Generation Space Size-------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gcnewcapacity $RESTCOMM_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "--------Garbage-collected heap-------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gc $RESTCOMM_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + fi + if [ -n "$RMS_PID" ]; then + echo "----------------------- mediaserver ---------------------------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "-------- New Generation Heap -------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gcnew $RMS_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "--------New Generation Space Size-------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gcnewcapacity $RMS_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "--------Garbage-collected heap-------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + jstat -gc $RMS_PID >> $LOGS_DIR_ZIP/jvm_process_$DATE + fi + echo "--------------------------------- ---------------------------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo "----------------------- More INFO ---------------------------" >> $LOGS_DIR_ZIP/jvm_process_$DATE + echo " http://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html " >> $LOGS_DIR_ZIP/jvm_process_$DATE +} +LWP_threads_logs () { + pat=`ps -ef | grep java | grep -v grep | awk '{print $2}'` + ps -eLo pid,lwp,nlwp,ruser,pcpu,stime,etime,args | grep -F "${pat}" > $LOGS_DIR_ZIP/lwpthread_$DATE.txt + return 0 +} +netstat_stats () { + echo "----------------------- netstat -s ---------------------------" > $LOGS_DIR_ZIP/netstat_stats_$DATE + netstat -s >> $LOGS_DIR_ZIP/netstat_stats_$DATE + echo >> $LOGS_DIR_ZIP/netstat_stats_$DATE + echo >> $LOGS_DIR_ZIP/netstat_stats_$DATE + echo "----------------------- netstat -anp ---------------------------" >> $LOGS_DIR_ZIP/netstat_stats_$DATE + netstat -anp >> $LOGS_DIR_ZIP/netstat_stats_$DATE +} +make_tar () { + echo TAR_FILE : $LOGS_DIR_ZIP.tar.gz + tar -zcf $LOGS_DIR_ZIP.tar.gz -C $LOGS_DIR_ZIP . 3>&1 1>&2 2>&3 + rm -rf $LOGS_DIR_ZIP +} +set_info() { + echo "$1" > $LOGS_DIR_ZIP/issue_info.txt +} +jvm_top() { + ./jvmtop.sh --once > $LOGS_DIR_ZIP/jvm_top.txt +} +sys_date() { + echo `date` > $LOGS_DIR_ZIP/sys_date.txt +} +getPID(){ + RESTCOMM_PID=$(jps | grep jboss-modules.jar | cut -d " " -f 1) + while read -r line + do + if ps -ef | grep $line | grep -q mediaserver + then + RMS_PID=$line + fi + done < <(jps | grep Main | cut -d " " -f 1) + if [[ -z "$RESTCOMM_PID" ]]; then + echo "RestComm is not Running, will try to collect all available logs" + fi + if [[ -z "$RMS_PID" ]]; then + echo "RMS is not Running, will try to collect all available logs" + fi +} +usage () { + cat << EOF +Usage: logs_collect.sh +options: +-m : optional message of the problem. +-t : Restcomm log file time extractor (e.g "06:20:0*,06:23:0*"). +-h : prints this message +-z : Create .tar file +EOF + exit 1 +} +#MAIN +tflag=false +zflag=false +TEMP=`getopt --long -o ":t:m:hz" "$@"` +eval set -- "$TEMP" +while true ; do + case "$1" in + -m ) + mkdir -p $LOGS_DIR_ZIP + set_info "$2" + shift 2 + ;; + -t ) + tflag=true + var=$2 + shift 2 + ;; + -z ) + zflag=true + break + ;; + -h ) + usage + ;; + *) + break + ;; + esac +done; +if [ ! -e $LOGS_DIR_ZIP ]; then + echo "create DIR $LOGS_DIR_ZIP" + mkdir -p $LOGS_DIR_ZIP +fi +if [ -d "$LOGS_DIR_ZIP" ]; then + getPID + restcomm_logs + rvd_logs + mediaserver_logs + system_logs + JVM_perfo_stats + jvm_process_info + LWP_threads_logs + system_usage_info + netstat_stats + jvm_top + sys_date + if $tflag ; then + restcomm_logs_bytime $var + fi + if $zflag ; then + make_tar + fi +else + echo "Directory $LOGS_DIR_ZIP not created, going to exit." + exit 1 +fi diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/mediaserver.conf b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/mediaserver.conf new file mode 100644 index 0000000000..4dfa3d8fed --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/mediaserver.conf @@ -0,0 +1,58 @@ +#! /bin/bash + +## Description: List of variables used to configure RestComm Media Server +## Author : Henrique Rosa (henrique.rosa@telestax.com) + +# Network +BIND_ADDRESS=127.0.0.1 +EXTERNAL_ADDRESS= +NETWORK=127.0.0.1 +SUBNET=255.255.255.255 +USE_SBC=true + +# MGCP Controller +MGCP_ADDRESS=127.0.0.1 +MGCP_PORT=2427 + +# Media +MEDIA_TIMEOUT=0 +MEDIA_MAX_DURATION=14440 +MEDIA_LOW_PORT=64534 +MEDIA_HIGH_PORT=65534 +MEDIA_JITTER_SIZE=50 +MEDIA_CODECS=pcmu,pcma,telephone-event + +# Resources +EXPECTED_LOAD=50 +AUDIO_CACHE_SIZE=100 +AUDIO_CACHE_ENABLED=false +DTMF_DETECTOR_DBI=-30 +DTMF_DETECTOR_TONE_DURATION=80 +DTMF_DETECTOR_TONE_INTERVAL=400 + +# DTLS +DTLS_MIN_VERSION=1.0 +DTLS_MAX_VERSION=1.2 +DTLS_CIPHER_SUITE=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +DTLS_CERTIFICATE=conf/dtls/x509-server-ecdsa.pem +DTLS_KEY=conf/dtls/x509-server-key-ecdsa.pem +DTLS_ALGORITHM=ecdsa + +# Logger +LOG_APPENDER_CONSOLE=INFO +LOG_APPENDER_FILE=INFO + +LOG_FILE_URL=log/server.log + +LOG_CATEGORY_MEDIA_SERVER='org.mobicents.media.server:INFO' +LOG_CATEGORY_MGCP='org.mobicents.media.control.mgcp:INFO' +LOG_CATEGORY_RTP='org.mobicents.media.server.impl.rtp:INFO' +LOG_CATEGORY_RTCP='org.mobicents.media.server.impl.rtcp:INFO' + +# SSL +SSL_ENABLED=false +SSL_KEYSTORE=restcomm.jks +SSL_PASSWORD=changeme + +# Java +MS_OPTS="-Xms2048m -Xmx2048m -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1RSetUpdatingPauseTimePercent=10 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=4m -XX:G1HeapWastePercent=5 -XX:InitiatingHeapOccupancyPercent=85 -XX:+UnlockExperimentalVMOptions -XX:G1MixedGCLiveThresholdPercent=85 -XX:+AlwaysPreTouch -XX:+UseCompressedOops -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dhttp.keepAlive=false -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../../mediaserver_dumpfile-$(date +%b_%d_%Y_%H_%M_%S).bin" diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/monitoring/Graylog_Monitoring.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/monitoring/Graylog_Monitoring.sh new file mode 100644 index 0000000000..9e28525f0e --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/monitoring/Graylog_Monitoring.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +SERVERLABEL="" +GRAYLOG_SERVER="" + +HDmonitor(){ + #Collect HD Data from Host + hdusage=`df -hP $PWD | awk '/[0-9]%/{print $(NF-1)}'` + #Send data to graylog + message={"\"host\"":"\"${SERVERLABEL}\"","\"message\"":"\"${hdusage}\""} + curl --connect-timeout 10 --max-time 15 -XPOST http://$GRAYLOG_SERVER:5555/gelf -p0 -d ${message} +} + + +RCJVMonitor(){ + #FInd RMS process number + rcprocess=$(jps | grep jboss-modules.jar | cut -d " " -f 1) + #Run JVMTOP + jvmvars=` $BASEDIR/../jvmtop.sh --once | grep ${rcprocess} | sed -e "s/ */ /g" | sed -e "s/%//g" | sed -e "s/m//g" | cut -f3,4,5,6,7,8 -d ' ' ` + #Send data to graylog + IFS=" " read HPCUR HPMAX NHCUR NHMAX CPU GC <<< $jvmvars + message={"\"host\"":"\"${SERVERLABEL}\"","\"message\"":"\"RC_JVM_STATS\"","\"_HPCUR\"":"${HPCUR}","\"_HPMAX\"":"${HPMAX}","\"_NHCUR\"":"${NHCUR}","\"_NHMAX\"":"${NHMAX}","\"_CPU\"":"${CPU}","\"_GC\"":"${GC}"} + curl --connect-timeout 10 --max-time 15 -XPOST http://$GRAYLOG_SERVER:7777/gelf -p0 -d ${message} +} + + +RMSJVMonitor(){ + #FInd RMS process number + while read -r line + do + if ps -ef | grep $line | grep -q mediaserver + then + msprocess=$line + fi + done < <(jps | grep Main | cut -d " " -f 1) + + #Run JVMTOP + jvmvars=` $BASEDIR/../jvmtop.sh --once | grep ${msprocess} | sed -e "s/ */ /g" | sed -e "s/%//g" | sed -e "s/m//g" | cut -f3,4,5,6,7,8 -d ' ' ` + #Send data to graylog + IFS=" " read HPCUR HPMAX NHCUR NHMAX CPU GC <<< $jvmvars + message={"\"host\"":"\"${SERVERLABEL}\"","\"message\"":"\"MS_JVM_STATS\"","\"_HPCUR\"":"${HPCUR}","\"_HPMAX\"":"${HPMAX}","\"_NHCUR\"":"${NHCUR}","\"_NHMAX\"":"${NHMAX}","\"_CPU\"":"${CPU}","\"_GC\"":"${GC}"} + curl --connect-timeout 10 --max-time 15 -XPOST http://$GRAYLOG_SERVER:7777/gelf -p0 -d ${message} +} + +SERVERAMonitor(){ + #Collect RAM from host data + MemTotal=`awk '( $1 == "MemTotal:" ) { print $2/1048576 }' /proc/meminfo` + MemFree=`awk '( $1 == "MemFree:" ) { print $2/1048576 }' /proc/meminfo` + Buffers=`awk '( $1 == "Buffers:" ) { print $2/1048576 }' /proc/meminfo` + Cache=`awk '( $1 == "Cached:" ) { print $2/1048576 }' /proc/meminfo` + SwapTotal=`awk '( $1 == "SwapTotal:" ) { print $2/1048576 }' /proc/meminfo` + SwapFree=`awk '( $1 == "SwapFree:" ) { print $2/1048576 }' /proc/meminfo` + + #Send data to graylog + message={"\"host\"":"\"${SERVERLABEL}\"","\"message\"":"\"Host_Heap\"","\"_MemTotal\"":"${MemTotal}","\"_MemFree\"":"${MemFree}","\"_Buffers\"":"${Buffers}","\"_Cache\"":"${Cache}","\"_SwapTotal\"":"${SwapTotal}","\"_SwapFree\"":"${SwapFree}"} + curl --connect-timeout 10 --max-time 15 -XPOST http://$GRAYLOG_SERVER:6666/gelf -p0 -d ${message} +} + +echo $1 +$1 diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restart-restcomm.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restart-restcomm.sh new file mode 100644 index 0000000000..90e9470a76 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restart-restcomm.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +## +## Descript+ion: Script that collects all necessary system logs and data. +## Author : Lefteris Banos +# + +JMAP="false" + +## +## FUNCTIONS +## +getPID(){ + RESTCOMM_PID=" " + RMS_PID="" + + RESTCOMM_PID=$(jps | grep jboss-modules.jar | cut -d " " -f 1) + + while read -r line + do + if ps -ef | grep $line | grep -q mediaserver + then + RMS_PID=$line + fi + done < <(jps | grep Main | cut -d " " -f 1) + +} + +stopRestComm(){ + echo "...stoping RestComm" + ./stop-restcomm.sh + + while [[ ! -z "$RESTCOMM_PID" || ! -z "$RMS_PID" ]]; do + getPID + echo "...waiting RestComm and MS to stop" + sleep 2 + done +} + +startRestComm(){ + echo "...starting RestComm" + ./start-restcomm.sh +} + +#MAIN +# parse the flag options (and their arguments) +while getopts "hmz" OPT; do + case "$OPT" in + h) + echo "Description: Collects system data. The output is a compressed file." + echo " " + echo "restart-restcomm.sh [options]" + echo " " + echo "options:" + echo "-m collect jmap" + echo "now will jusr restart Restcomm right now" + echo "-h show brief help" + exit 0 + ;; + m) + JMAP="true" + ;; + now) + JMAP="false" + ;; + ?) + echo "Invalid option: $OPTARG" + echo "Type \"restart-restcomm.sh -help\" for instructions" + exit 1 ;; + esac +done + +# get rid of the just-finished flag arguments +shift $(($OPTIND-1)) + + +if [ "$JMAP" == "true" ]; then + echo "...JMAP files will be collected" + ./collect_jmap.sh +fi + +stopRestComm +sleep 2 +startRestComm diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf new file mode 100755 index 0000000000..904492ae42 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf @@ -0,0 +1,149 @@ +#! /bin/bash + +## +## Description: List of variables used to configure RestComm +## Author : Henrique Rosa +## Author : George Vagenas +## + +# Network configuration +NET_INTERFACE='' +PRIVATE_IP='' +SUBNET_MASK='' +NETWORK='' +BROADCAST_ADDRESS='' +# PUBLIC IP ADDRESS +STATIC_ADDRESS='' +#hostname of the server to be used at restcomm.xml. If not set the STATIC_ADDRESS will be used. +RESTCOMM_HOSTNAME='' + +# Media Server +#Media server running external (different node than Restcomm)] +MS_EXTERNAL=false +#MS IP ADDRESS if using different IP from RestComm +MS_ADDRESS='' +#Values rms: RestComm Media Server, xms: Dialogic Media Server +MS_COMPATIBILITY_MODE=rms +LOCALMGCP=2727 +REMOTEMGCP=2427 +MGCP_RESPONSE_TIMEOUT=500 +RECORDINGS_PATH='' + +# Activate music on conference when participants==1 +PLAY_WAIT_MUSIC='TRUE' + +# Address for outbound calls +OUTBOUND_PROXY='' #Provide port if different than 5060 +OUTBOUND_PROXY_USERNAME='' +OUTBOUND_PROXY_PASSWORD='' + +# Push notification server +PUSH_NOTIFICATION_SERVER_ENABLED=false +PUSH_NOTIFICATION_SERVER_URL='' +PUSH_NOTIFICATION_SERVER_DELAY='' + +# Outbound proxy for SMS +SMS_PREFIX='#' #For VoipInnovation you will need the '#' character for SMS Prefix +SMS_OUTBOUND_PROXY='' #Please provide port if different than 5060 + +# Connection details for SMPP Restcomm integration +SMPP_ACTIVATE='false' #default SMPP activate is always false. Set to true to activate SMPP +SMPP_SYSTEM_ID='' +SMPP_PASSWORD='' +SMPP_SYSTEM_TYPE='' +SMPP_PEER_IP='' #use IP or DNS name of peer SMPP server +SMPP_PEER_PORT='' +SMPP_SOURCE_MAP='' +SMPP_DEST_MAP='' + +# DID Provision provider variable declarations +PROVISION_PROVIDER='' # values: VI (VoipInnovation), BW (Bandwidth), NX (Nexmo), VB (Voxbone) +#Username and password for all supported DID provision providers +DID_LOGIN='' +DID_PASSWORD='' +# VoipInnovation Endpoint ID +DID_ENDPOINT='' +#Bandwidth SiteId and AccountId +DID_SITEID='' +DID_ACCOUNTID='' + +#Port to be used at the DID URI from provider when buying number. Empty for SRV records. +#Normally set same as the external TCP-SIP port. +DID_URIPORT='' + +# Interfax variable declarations. +INTERFAX_USER='' +INTERFAX_PASSWORD='' + +# ISpeech variable declarations. +ISPEECH_KEY='' + +#Configure TTS system to use. Accepted values:voicerss,acapela +TTSSYSTEM='voicerss' + +# VoiceRSS variable declarations +VOICERSS_KEY='' + +# Acapela variable declarations. +ACAPELA_APPLICATION='' +ACAPELA_LOGIN='' +ACAPELA_PASSWORD='' + +# AWS Polly variable declarations. +AWS_ACCESS_KEY='' +AWS_SECRET_KEY='' +AWS_REGION='' + +#RestComm PORT configuration +HTTP_PORT='8080' #Port used for HTTP. Default 8080 +HTTPS_PORT='8443' #Port used for HTTPS. Default 8443 +#Connectors port configuration. !!IMPORTANT!! If LB is used this ports will be used from LB to send traffic to RC.Under LB this port +SIP_PORT_UDP='5080' #LB UDP port. Default is 5080 +SIP_PORT_TCP='5080' #LB TCP port. Default is 5080 +SIP_PORT_TLS='5081' #LB TLS port. Default is 5081 +SIP_PORT_WS='5082' #LB WS port. Default is 5082 +SIP_PORT_WSS='5083' #LB WSS port. Default is 5083 +#Port Offset Used when more that one RC is running on the same machine. To avoid port conflicts +#E.g. If set PORT_OFFSET='100' all configured ports will be accessible from PORT+100. +PORT_OFFSET='0' #Port offset configurations. Default '0'. + +#LOGS level. Usual values : WARN,INFO,DEBUG +LOG_LEVEL='INFO' #Used for RMS & RC console-handler. +LOG_LEVEL_COMPONENT_GOVNIST='INFO' #Log level for "gov.nist" module +LOG_LEVEL_COMPONENT_SIPSERVLET='INFO' #Log level for "org.mobicents.servlet.sip" module +LOG_LEVEL_COMPONENT_SIPRESTCOMM='INFO' #Log level for "org.mobicents.servlet.sip.restcomm" module +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' + +#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="" + +#DNS Provisioning configuration, for more info read configuration documentation +#http://documentation.telestax.com/connect/configuration/index.html#Configuration +DNS_PROVISIONING_CLASS="" +DNS_PROVISIONING_ENABLED="FALSE" +DNS_PROVISIONING_AWS_ROUTE53_A_VALUE="" +DNS_PROVISIONING_AWS_ROUTE53_SRV_VALUE="" +DNS_PROVISIONING_AWS_ROUTE53_ACCESS_KEY="" +DNS_PROVISIONING_AWS_ROUTE53_SECRET_KEY="" +DNS_PROVISIONING_AWS_ROUTE53_REGION="" +DNS_PROVISIONING_AWS_ROUTE53_TTL="" +DNS_PROVISIONING_AWS_ROUTE53_HOSTED_ZONE_ID="" +DNS_PROVISIONING_AWS_ROUTE53_IS_ALIAS="" +DNS_PROVISIONING_AWS_ROUTE53_ALIAS_EVALUATE_TARGET_HEALTH="" +DNS_PROVISIONING_AWS_ROUTE53_ALIAS_HOSTED_ZONE_ID="" + +#CONFERENCE_TIMEOUT is allowed life of a conference in restcomm +#after that all participants will be asked to leave and conference will be closed. +#default value is 14400 seconds/(4 hours).Please provide value in seconds +CONFERENCE_TIMEOUT="14400" + +#SDR Service configuration +SDR_SERVICE_CLASS='' +SDR_SERVICE_HTTP_URI='' +SDR_SERVICE_AMQP_URI='' \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/set-log-level.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/set-log-level.sh new file mode 100644 index 0000000000..e3acd40f3b --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/set-log-level.sh @@ -0,0 +1,114 @@ +#!/bin/bash +## Description: Set log_level on the fly +## Author: Lefteris Banos +##Using Jboss Command Line Interface - CLI (https://developer.jboss.org/wiki/CommandLineInterface) + + +# VARIABLES +BASE_DIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +RESTCOMM_BIN=$BASE_DIR/.. +CLIFILE=$BASE_DIR/log.cli + + +changelog() { + cat <> $CLIFILE + /subsystem=logging/logger=$1:write-attribute(name=level,value=$2) +EOT +} + +changelogROOT() { + cat <> $CLIFILE + /subsystem=logging/root-logger=$1:write-attribute(name=level,value=$2) +EOT +} + +changelogCONSOLE() { + cat <> $CLIFILE + /subsystem=logging/console-handler=$1:write-attribute(name=level,value=$2) +EOT +} + + +listlog(){ + cat <> $CLIFILE +/subsystem=logging/logger=org.mobicents.servlet.sip:read-resource +/subsystem=logging/logger=org.mobicents.servlet.sip.restcomm:read-resource +/subsystem=logging/logger=org.restcomm.connect:read-resource +/subsystem=logging/logger=gov.nist:read-resource +/subsystem=logging/console-handler=CONSOLE:read-resource +/subsystem=logging/root-logger=ROOT:read-resource +EOT +} + +if [ $# -eq 0 ] + then + arr="help" +else + arr=( "$@" ) +fi + +for compt in $arr + do + case "$compt" in + servlet) + COMPONENT=org.mobicents.servlet.sip + changelog $COMPONENT $2 + ;; + + govnist) + COMPONENT=gov.nist + changelog $COMPONENT $2 + ;; + siprestcomm) + COMPONENT=org.mobicents.servlet.sip.restcomm + changelog $COMPONENT $2 + ;; + restcomm) + COMPONENT=org.restcomm.connect + changelog $COMPONENT $2 + # update RVD's logging level too. TODO do this separately on 'rvd)' when docker scripts are updated too + COMPONENT=org.restcomm.connect.rvd.LOCAL + changelog $COMPONENT $2 + COMPONENT=org.restcomm.connect.rvd.GLOBAL + changelog $COMPONENT $2 + ;; + rvd) + COMPONENT=org.restcomm.connect.rvd.LOCAL + changelog $COMPONENT $2 + COMPONENT=org.restcomm.connect.rvd.GLOBAL + changelog $COMPONENT $2 + ;; + root) + COMPONENT=ROOT + changelogROOT $COMPONENT $2 + ;; + console) + COMPONENT=CONSOLE + changelogCONSOLE $COMPONENT $2 + ;; + list) + listlog + ;; + *) + echo "Usage: $0 \"servlet govnist siprestcomm restscomm console root\" DEBUG. Can also set each element individually" + echo "Usage: $0 list (To list the actual log levels)" + exit 1 + esac +done + + n=0 + until [ $n -ge 5 ] + do + n=$[$n+1] + $RESTCOMM_BIN/jboss-cli.sh --connect controller=127.0.0.1 --file="$CLIFILE" # substitute your command here + if [ $? -eq 0 ]; then echo "LOG level changed properly" && break; fi + + if [ $n -eq 5 ]; then echo "Command Fail.. please try again"; fi + sleep 2 + done + + + +rm $CLIFILE + + diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-mediaserver.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-mediaserver.sh new file mode 100755 index 0000000000..cadee45e16 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-mediaserver.sh @@ -0,0 +1,19 @@ +#! /bin/bash + +## Description: Starts Media Server with auto-configuration. +## Author : Henrique Rosa (henrique.rosa@telestax.com) + +startMediaServer() { + local basedir=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) + local ms_conf=$basedir/mediaserver.conf + local ms_home=$RESTCOMM_HOME/mediaserver + + chmod +x $ms_home/*.sh + chmod +x $ms_home/.autoconfig/*.sh + chmod +x $ms_home/.autoconfig/autoconfig.d/*.sh + chmod +x $ms_home/bin/*.sh + + $ms_home/start-mediaserver.sh $ms_conf +} + +startMediaServer diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh new file mode 100755 index 0000000000..ae6ba7538e --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/start-restcomm.sh @@ -0,0 +1,165 @@ +#! /bin/bash +## +## Description: Starts RestComm with auto-configuration. +## +## Parameters : 1. Bind Address (default: 127.0.0.1) +## 2. Run Mode [standalone|standalone-lb|domain|domain-lb] (default:standalone) +## +## Author : Henrique Rosa +## +# set environment variables for execution +BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +RESTCOMM_HOME=$(cd $BASEDIR/../../ && pwd) +MMS_HOME=$RESTCOMM_HOME/mediaserver +LB_HOME=$RESTCOMM_HOME/tools/sip-balancer + +## +## FUNCTIONS +## +startRestcomm() { + run_mode="$1" + bind_address="$2" + ExtraOpts="-Djboss.bind.address.management=127.0.0.1" + + # Check if RestComm is already running + if tmux ls | grep -q 'restcomm'; then + echo 'TelScale RestComm is already running on terminal session "restcomm"!' + exit 1; + fi + + if [ -n "$MGMT_PASS" ] && [ -n "$MGMT_USER" ]; then + echo "MGMT_PASS, MGMT_USER is set will be added to MGMNT configuration" + grep -q "$MGMT_USER" $RESTCOMM_HOME/standalone/configuration/mgmt-users.properties || $RESTCOMM_HOME/bin/add-user.sh "$MGMT_USER" "$MGMT_PASS" -s + #Management bind address + ExtraOpts="-Djboss.bind.address.management=$bind_address" + fi + + case $run_mode in + 'standalone'*) + # start restcomm on standalone mode + chmod +x $RESTCOMM_HOME/bin/standalone.sh + echo 'TelScale RestComm started running on standalone mode. Terminal session: restcomm.' + echo "Using IP Address: $BIND_ADDRESS" + if [[ "$RUN_DOCKER" == "true" || "$RUN_DOCKER" == "TRUE" ]]; then + $RESTCOMM_HOME/bin/standalone.sh -b $bind_address "${ExtraOpts}" + else + tmux new -s restcomm -d "$RESTCOMM_HOME/bin/standalone.sh -b $bind_address ${ExtraOpts}" + fi + ;; + 'domain'*) + # start restcomm on standalone mode + chmod +x $RESTCOMM_HOME/bin/domain.sh + tmux new -s restcomm -d "$RESTCOMM_HOME/bin/domain.sh -b $bind_address ${ExtraOpts}" + echo 'TelScale RestComm started running on domain mode. Screen session: restcomm.' + echo "Using IP Address: $BIND_ADDRESS" + ;; + *) + # start restcomm on standalone mode + chmod +x $RESTCOMM_HOME/bin/standalone.sh + tmux new -s restcomm -d "$RESTCOMM_HOME/bin/standalone.sh -b $bind_address ${ExtraOpts}" + echo 'TelScale RestComm started running on standalone mode. Screen session: restcomm.' + echo "Using IP Address: $BIND_ADDRESS" + ;; + esac + +} + +verifyDependencies() { + source $BASEDIR/verify-dependencies.sh +} + +loadConfigurationParams() { + source $BASEDIR/restcomm.conf + source $BASEDIR/advanced.conf +} + +## +## MAIN +## +verifyDependencies +loadConfigurationParams + +echo BASEDIR: $BASEDIR +echo RESTCOMM_HOME: $RESTCOMM_HOME + +# input parameters and default values +RUN_MODE='standalone' +BIND_ADDRESS='' + +while getopts "s:r:i:" optname +do + case "$optname" in + "s") + STATIC_ADDRESS="$OPTARG" + ;; + "r") + RUN_MODE="$OPTARG" + ;; + "i") + NET_INTERFACE="$OPTARG" + ;; + ":") + echo "No argument value for option $OPTARG" + exit 1 + ;; + "?") + echo "Unknown option $OPTARG" + exit 1 + ;; + *) + echo 'Unknown error while processing options' + exit 1 + ;; + esac +done + +# validate network interface and extract network properties +if [[ -z "$NET_INTERFACE" ]]; then +NET_INTERFACE='eth0' +echo "Looking for the appropriate interface" + NET_INTERFACES=$(ifconfig | expand | cut -c1-8 | sort | uniq -u | awk -F: '{print $1;}') + if [[ -z $(echo $NET_INTERFACES | sed -n "/$NET_INTERFACE/p") ]]; then + echo "The network interface $NET_INTERFACE is not available or does not exist." + echo "The list of available interfaces is: $NET_INTERFACES" + exit 1 + fi +fi + +# load network properties for chosen interface +if [[ -z "$PRIVATE_IP" || -z "$SUBNET_MASK" || -z "$NETWORK" || -z "$BROADCAST_ADDRESS" ]]; then +echo "Looking for the IP Address, subnet, network and broadcast_address" + source $BASEDIR/utils/read-network-props.sh "$NET_INTERFACE" +fi + +BIND_ADDRESS="$PRIVATE_IP" +BIND_NETWORK="$NETWORK" +BIND_SUBNET_MASK="$SUBNET_MASK" + +if [[ -z "$STATIC_ADDRESS" ]]; then + STATIC_ADDRESS=$BIND_ADDRESS +fi + +if [[ -z "$MEDIASERVER_EXTERNAL_ADDRESS" ]]; then + MEDIASERVER_EXTERNAL_ADDRESS="$STATIC_ADDRESS" +fi + +if [[ -z "$PUBLIC_IP" ]]; then + PUBLIC_IP=$STATIC_ADDRESS +fi + +if [[ -z "$SMS_OUTBOUND_PROXY" ]]; then + SMS_OUTBOUND_PROXY=$OUTBOUND_PROXY +fi + +# configure restcomm installation + +if [[ "$MANUAL_SETUP" == "false" || "$MANUAL_SETUP" == "FALSE" ]]; then + source $BASEDIR/autoconfigure.sh +fi + +if [[ "$MS_EXTERNAL" == "false" || "$MS_EXTERNAL" == "FALSE" ]]; then + source $BASEDIR/start-mediaserver.sh +fi +# start restcomm in selected run mode +startRestcomm "$RUN_MODE" "$BIND_ADDRESS" +exit 0 diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-mediaserver.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-mediaserver.sh new file mode 100755 index 0000000000..a8f2904939 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-mediaserver.sh @@ -0,0 +1,11 @@ +#! /bin/bash + +## Description: Stops Media Server running in a terminal session. +## Author : Henrique Rosa (henrique.rosa@telestax.com) + +stopMediaServer() { + local ms_home=$RESTCOMM_HOME/mediaserver + $ms_home/stop-mediaserver.sh +} + +stopMediaServer diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-restcomm.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-restcomm.sh new file mode 100755 index 0000000000..6c91d6232d --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/stop-restcomm.sh @@ -0,0 +1,26 @@ +#! /bin/bash +## +## Description: Stops RestComm and Media Server processes running on terminal sessions +## Authors : Henrique Rosa (henrique.rosa@telestax.com) +## + +BASEDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) +RESTCOMM_HOME=$(cd $BASEDIR/../../ && pwd) +MS_HOME=$RESTCOMM_HOME/mediaserver + +stopMediaServer() { + source $BASEDIR/stop-mediaserver.sh +} + +stopRestComm() { + echo 'Shutting down RestComm...' + if tmux ls | grep -q 'restcomm'; then + tmux kill-session -t restcomm + echo '...stopped RestComm instance running on terminal session "restcomm"!' + else + echo '...restComm already stopped!' + fi +} + +stopMediaServer +stopRestComm diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/telestax-license.xml b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/telestax-license.xml new file mode 100644 index 0000000000..31b1d5ee70 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/telestax-license.xml @@ -0,0 +1,6 @@ + + + true + + + diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/utils/read-network-props.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/utils/read-network-props.sh new file mode 100644 index 0000000000..096a496be7 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/utils/read-network-props.sh @@ -0,0 +1,48 @@ +#!/bin/bash +## +## Description : Utility script to find network properties +## Author : Henrique Rosa - henrique.rosa@telestax.com +## + +# VARIABLES +IP_ADDRESS_PATTERN="[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}" +INTERFACE="$1" + +## Description: Gets the private IP of the instance +## Parameters : none +getPrivateIP() { + echo "$INET_DATA" | grep -o "addr:$IP_ADDRESS_PATTERN" | awk -F: '{print $2}' +} + +## Description: Gets the broadcast address of the instance +## Parameters : none +getBroadcastAddress() { + echo "$INET_DATA" | grep "Bcast:$IP_ADDRESS_PATTERN" | awk '{print $3}' | awk -F: '{print $2}' +} + +## Description: Gets the Subnet Mask of the instance +## Parameters : none +getSubnetMask() { + /sbin/ifconfig $INTERFACE | grep "Mask:$IP_ADDRESS_PATTERN" | awk '{print $4}' | awk -F: '{print $2}' +} + +## Description: Gets the Network of the instance +## Parameters : 1.Private IP +## 2.Subnet Mask +getNetwork() { + #debian/ubuntu + NW=`ipcalc -n $1 $2 | grep -i "Network" | awk '{print $2}' | awk -F/ '{print $1}';` + if [[ -z "$NW" ]]; then + #rhel/centos/amazon + NW=`ipcalc -n $1 $2 | grep -i "Network" | awk -F= '{print $2}';` + fi + echo $NW +} + +# MAIN +INET_DATA=$(/sbin/ifconfig $INTERFACE | grep "inet ") + +PRIVATE_IP=$(getPrivateIP) +SUBNET_MASK=$(getSubnetMask) +NETWORK=$(getNetwork $PRIVATE_IP $SUBNET_MASK) +BROADCAST_ADDRESS=$(getBroadcastAddress) diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/verify-dependencies.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/verify-dependencies.sh new file mode 100755 index 0000000000..dbf06b3195 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/verify-dependencies.sh @@ -0,0 +1,56 @@ +#!/bin/bash +## Description: Verifies if all dependencies are installed. +## Author: Henrique Rosa (henrique.rosa@telestax.com) + +verifyJava() { + if [ -n "$(which java)" ]; then + if [ $(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d'.' -f2) -ne "7" ]; then + echo "Only Java 1.7 required." + exit 1 + fi + else + echo "Java dependency is missing." + echo "CentOS/RHEL: java-1.7.0-openjdk-devel.x86_64" + echo "Debian/Ubuntu:" + echo " add-apt-repository ppa:openjdk-r/ppa" + echo " apt-get update" + echo " apt-get install openjdk-7-jdk" + echo "macOS: brew cask install java7" + exit 1 + fi +} + +verifyTmux() { + if [ -z "$(which tmux)" ]; then + echo "TMux dependency is missing." + echo "CentOS/RHEL: yum install tmux" + echo "Debian/Ubuntu: apt-get install tmux" + echo "macOS: brew install tmux" + exit 1 + fi +} + +verifyXmlstarlet() { + if [ -z "$(which xmlstarlet)" ]; then + echo "XML Starlet dependency is missing." + echo "CentOS/RHEL: yum install xmlstarlet" + echo "Debian/Ubuntu: apt-get install xmlstarlet" + echo "macOS: brew install xmlstarlet" + exit 1 + fi +} + +verifyIpcalc() { + if [ -z "$(which ipcalc)" ]; then + echo "IP Calc dependency is missing." + echo "CentOS/RHEL: yum install ipcalc" + echo "Debian/Ubuntu: apt-get install ipcalc" + echo "macOS: brew install ipcalc" + exit 1 + fi +} + +verifyJava +verifyTmux +verifyXmlstarlet +verifyIpcalc diff --git a/restcomm/configuration/mms-run.sh b/restcomm/configuration/mms-run.sh new file mode 100755 index 0000000000..12e69a8c36 --- /dev/null +++ b/restcomm/configuration/mms-run.sh @@ -0,0 +1,186 @@ +#!/bin/sh +### ====================================================================== ### +## ## +## Mobicents Media Server Bootstrap Script ## +## ## +### ====================================================================== ### + +### $Id: run.sh abhayani@redhat.com $ ### + +DIRNAME=`dirname $0` +PROGNAME=`basename $0` +GREP="grep" + +# Use the maximum available, or set MAX_FD != -1 to use that +MAX_FD="maximum" + +# +# Helper to complain. +# +warn() { + echo "${PROGNAME}: $*" +} + +# +# Helper to puke. +# +die() { + warn $* + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false; +darwin=false; +linux=false; +case "`uname`" in + CYGWIN*) + cygwin=true + ;; + + Darwin*) + darwin=true + ;; + + Linux) + linux=true + ;; +esac + + +# Force IPv4 on Linux systems since IPv6 doesn't work correctly with jdk5 and lower +if [ "$linux" = "true" ]; then + JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true" +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$MMS_HOME" ] && + MMS_HOME=`cygpath --unix "$MMS_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$JAVAC_JAR" ] && + JAVAC_JAR=`cygpath --unix "$JAVAC_JAR"` +fi + +# Setup MMS_HOME +if [ "x$MMS_HOME" = "x" ]; then + # get the full path (without any relative bits) + MMS_HOME=`cd $DIRNAME/..; pwd` +fi +export MMS_HOME + +# Increase the maximum file descriptors if we can +if [ "$cygwin" = "false" ]; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ]; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then + # use the system max + MAX_FD="$MAX_FD_LIMIT" + fi + + ulimit -n $MAX_FD + if [ $? -ne 0 ]; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query system maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# Setup the JVM +if [ "x$JAVA" = "x" ]; then + if [ "x$JAVA_HOME" != "x" ]; then + JAVA="$JAVA_HOME/bin/java" + else + JAVA_HOME=$(readlink -f /usr/bin/java | sed "s:bin/java::") + JAVA_HOME=$JAVA_HOME/.. + JAVA="java" + fi +fi + +# Setup the classpath +runjar="$MMS_HOME/bin/run.jar" +if [ ! -f "$runjar" ]; then + die "Missing required file: $runjar" +fi + +MMS_BOOT_CLASSPATH="$runjar" + +if [ "x$MMS_CLASSPATH" = "x" ]; then + MMS_CLASSPATH="$MMS_BOOT_CLASSPATH" +else + MMS_CLASSPATH="$MMS_CLASSPATH:$MMS_BOOT_CLASSPATH" +fi + + +# If -server not set in JAVA_OPTS, set it, if supported +SERVER_SET=`echo $JAVA_OPTS | $GREP "\-server"` +if [ "x$SERVER_SET" = "x" ]; then + + # Check for SUN(tm) JVM w/ HotSpot support + if [ "x$HAS_HOTSPOT" = "x" ]; then + HAS_HOTSPOT=`"$JAVA" -version 2>&1 | $GREP -i HotSpot` + fi + + # Enable -server if we have Hotspot, unless we can't + if [ "x$HAS_HOTSPOT" != "x" ]; then + # MacOS does not support -server flag + if [ "$darwin" != "true" ]; then + JAVA_OPTS="-server $JAVA_OPTS" + fi + fi +fi + +# Setup MMS specific properties +JAVA_OPTS="-Dprogram.name=$PROGNAME $JAVA_OPTS" +JAVA_OPTS="$JAVA_OPTS -Xms1024m -Xmx2048m -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000" +#JAVA_OPTS="$JAVA_OPTS -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n" + +# Setup the java endorsed dirs +MMS_ENDORSED_DIRS="$MMS_HOME/lib" +if [ "x$JAVA_HOME" != "x" ]; then + if [ -d "$JAVA_HOME/jre/lib/ext" ]; then + MMS_ENDORSED_DIRS="$MMS_ENDORSED_DIRS:$JAVA_HOME/jre/lib/ext" + else + echo 'ERROR: The extension lib for Java does not exist. Please configure $JAVA_HOME/jre/lib/ext' + exit 1 + fi +fi + +# Setup path for native libs +LD_LIBRARY_PATH="$MMS_HOME/native" +export LD_LIBRARY_PATH + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + MMS_HOME=`cygpath --path --windows "$MMS_HOME"` + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + MMS_CLASSPATH=`cygpath --path --windows "$MMS_CLASSPATH"` + MMS_ENDORSED_DIRS=`cygpath --path --windows "$MMS_ENDORSED_DIRS"` +fi + +# Display our environment +echo "=========================================================================" +echo "" +echo " MMS Bootstrap Environment" +echo "" +echo " MMS_HOME: $MMS_HOME" +echo "" +echo " JAVA: $JAVA" +echo "" +echo " JAVA_OPTS: $JAVA_OPTS" +echo "" +echo " CLASSPATH: $MMS_CLASSPATH" +echo "" +echo "=========================================================================" +echo "" + + "$JAVA" $JAVA_OPTS \ + -Djava.ext.dirs="$MMS_ENDORSED_DIRS" \ + -Dmbrola.base="$MMS_HOME/mbrola" \ + -classpath "$MMS_CLASSPATH" \ + org.mobicents.media.server.bootstrap.Main "$@" + MMS_STATUS=$? + +#java -Djava.ext.dirs=`pwd`/lib -Dmms.home=. -cp .:mms-standalone-2.0.0.BETA1-SNAPSHOT.jar org.mobicents.media.server.bootstrap.jmx.JMXMain diff --git a/restcomm/configuration/mms-server-beans.xml b/restcomm/configuration/mms-server-beans.xml new file mode 100644 index 0000000000..8eaf06e2cf --- /dev/null +++ b/restcomm/configuration/mms-server-beans.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + 127.0.0.1 + 127.0.0.1 + + 127.0.0.1 + 255.255.255.255 + false + 0 + 34534 + 65535 + + + + + + + + + + + + 50 + + + + + + + + org.mobicents.media.server.impl.dsp.audio.l16.Encoder + org.mobicents.media.server.impl.dsp.audio.l16.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Decoder + org.mobicents.media.server.impl.dsp.audio.g729.Encoder + org.mobicents.media.server.impl.dsp.audio.g729.Decoder + org.mobicents.media.server.impl.dsp.audio.gsm.Encoder + org.mobicents.media.server.impl.dsp.audio.gsm.Decoder + + + + + + + + + + + + 5 + 5 + 5 + 0 + 0 + 0 + 10 + 10 + 0 + + + + + + 2427 + + + mgcp-conf.xml + 25 + + + + + + + + + 1 + + + + + + + + mobicents/ivr/ + org.mobicents.media.core.endpoints.impl.IvrEndpoint + 50 + + + + mobicents/cnf/ + org.mobicents.media.core.endpoints.impl.ConferenceEndpoint + 50 + + + + mobicents/bridge/ + org.mobicents.media.core.endpoints.impl.BridgeEndpoint + 50 + + + + mobicents/relay/ + org.mobicents.media.core.endpoints.impl.PacketRelayEndpoint + 50 + + + + + + diff --git a/release/mobicents-dar.properties b/restcomm/configuration/mobicents-dar.properties similarity index 100% rename from release/mobicents-dar.properties rename to restcomm/configuration/mobicents-dar.properties diff --git a/restcomm/configuration/mobicents_build.xml b/restcomm/configuration/mobicents_build.xml new file mode 100755 index 0000000000..f24db8e38c --- /dev/null +++ b/restcomm/configuration/mobicents_build.xml @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading HSQLDB Driver for Tomcat version: ${mobicents-sipservlets.version} + + + + + + + + + Downloading mobicents SipServlets Tomcat version: ${mobicents-sipservlets-as7.version} + + + + + + + + + + Downloading mobicents SipServlets JBoss AS7 version: ${mobicents-sipservlets-as7.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading mobicents Media version: ${mobicents-media.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Downloading mobicents Diameter version: ${mobicents-diameter.version} + + + + + + + + + + + + + Building mobicents Restcomm + Restcomm workspace dir: "${workspace.mobicents-restcomm.dir}" + + + + + + + + + + + + + Copy restcomm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/restcomm/configuration/mss-sip-stack.properties b/restcomm/configuration/mss-sip-stack.properties new file mode 100644 index 0000000000..d677a45474 --- /dev/null +++ b/restcomm/configuration/mss-sip-stack.properties @@ -0,0 +1,41 @@ +gov.nist.javax.sip.LOG_MESSAGE_CONTENT=true +gov.nist.javax.sip.LOG4J_LOGGER_NAME=gov.nist +gov.nist.javax.sip.TRACE_LEVEL=LOG4J +gov.nist.javax.sip.DEBUG_LOG=logs/mss-jsip-debuglog.txt +gov.nist.javax.sip.SERVER_LOG=logs/mss-jsip-messages.xml +javax.sip.STACK_NAME=Restcomm-SIP-Servlets +javax.sip.AUTOMATIC_DIALOG_SUPPORT=off +gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY=true +gov.nist.javax.sip.THREAD_POOL_SIZE=64 +gov.nist.javax.sip.REENTRANT_LISTENER=true +# prevent DOS attacks +gov.nist.javax.sip.MAX_LISTENER_RESPONSE_TIME=120 +gov.nist.javax.sip.MAX_MESSAGE_SIZE=40000 +# setting up the buffer size to reduce retransmissions and avoid loosing messages +gov.nist.javax.sip.RECEIVE_UDP_BUFFER_SIZE=131072 +gov.nist.javax.sip.SEND_UDP_BUFFER_SIZE=131072 +gov.nist.javax.sip.AGGRESSIVE_CLEANUP=true +gov.nist.javax.sip.MAX_FORK_TIME_SECONDS=0 +# set to true so that the stack do more validation on dialog, +# but won't work on chained applications so false by default +gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING=false +gov.nist.javax.sip.MESSAGE_PROCESSOR_FACTORY=gov.nist.javax.sip.stack.NioMessageProcessorFactory +org.mobicents.servlet.sip.USER_AGENT_HEADER=Restcomm MAJOR_VERSION_NUMBER.BUILD_NUMBER +org.mobicents.servlet.sip.SERVER_HEADER=Restcomm MAJOR_VERSION_NUMBER.BUILD_NUMBER +#Uncomment the following line to enable Congestion Control +#gov.nist.javax.sip.SIP_MESSAGE_VALVE=org.mobicents.ext.javax.sip.congestion.CongestionControlMessageValve +org.mobicents.ext.javax.sip.congestion.SIP_SCANNERS= +org.mobicents.ext.javax.sip.congestion.CONGESTION_CONTROL_MONITOR_INTERVAL=-1 +#org.mobicents.ext.javax.sip.congestion.MEMORY_THRESHOLD", "85"); +#org.mobicents.ext.javax.sip.congestion.BACK_TO_NORMAL_MEMORY_THRESHOLD", "80"); +#org.mobicents.ext.javax.sip.congestion.CPU_PROCESS_THRESHOLD", "85"); +#org.mobicents.ext.javax.sip.congestion.BACK_TO_NORMAL_CPU_PROCESS_THRESHOLD", "80"); +#org.mobicents.ext.javax.sip.congestion.SERVER_TRANSACTIONS_THRESHOLD", "15000"); +#org.mobicents.ext.javax.sip.congestion.BACK_TO_NORMAL_SERVER_TRANSACTIONS_THRESHOLD", "10000"); +#org.mobicents.ext.javax.sip.congestion.DIALOGS_THRESHOLD", "200000"); +#org.mobicents.ext.javax.sip.congestion.BACK_TO_NORMAL_DIALOGS_THRESHOLD", "180000"); +#Uncomment the following line to work with the Mobicents Load Balancer +#org.mobicents.ha.javax.sip.BALANCERS=127.0.0.1 +org.mobicents.ha.javax.sip.LOCAL_HTTP_PORT=8080 +org.mobicents.ha.javax.sip.LOCAL_SSL_PORT=8443 +#org.mobicents.ha.javax.sip.REACHABLE_CHECK= diff --git a/release/setenv.sh b/restcomm/configuration/setenv.sh similarity index 100% rename from release/setenv.sh rename to restcomm/configuration/setenv.sh diff --git a/restcomm/configuration/telestax-license.xml b/restcomm/configuration/telestax-license.xml new file mode 100644 index 0000000000..f8aff59384 --- /dev/null +++ b/restcomm/configuration/telestax-license.xml @@ -0,0 +1,22 @@ + + + + + + true + smtp.googlemail.com + 465 + telscale-LI@telestax.com + ufrgwluolrorbtco + telscale-license@telestax.com + true + + + online + TelScale-RestComm + + + + + + diff --git a/restcomm/pom.xml b/restcomm/pom.xml index 15c1a27835..349af0843c 100644 --- a/restcomm/pom.xml +++ b/restcomm/pom.xml @@ -1,15 +1,20 @@ - - 4.0.0 - - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT - pom - RestComm - A unified communications platform for web developers. - http://www.restcomm.org + + 4.0.0 + + + org.restcomm + restcomm-parent + 4.0.1 + + + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT + pom + RestComm-Connect + A unified communications platform for web developers. + http://www.restcomm.org @@ -55,25 +60,28 @@ - scm:git:git@bitbucket.org:telestax/telscale-restcomm.git - scm:git:git@bitbucket.org:telestax/telscale-restcomm.git - https://bitbucket.org/telestax/telscale-restcomm - HEAD + scm:git:https://github.com/RestComm/Restcomm-Connect.git + scm:git:git@github.com:RestComm/Restcomm-Connect.git + https://github.com/RestComm/Restcomm-Connect - telscale-releases-repository - TelScale Releases Repository - http://telestax.artifactoryonline.com/telestax/releases + restcomm-releases-repository + Restcomm Releases Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2 + - telscale-snapshots-repository - TelScale Snapshots Repository - http://telestax.artifactoryonline.com/telestax/snapshots + restcomm-snapshots-repository + Restcomm Snapshots Repository + https://oss.sonatype.org/content/repositories/snapshots + + UTF-8 + 2.10.1 2.1.2 14.0.1 @@ -81,41 +89,56 @@ 1.5.5 1.7 2.4 - 1.0 + 1.10 + 2.6 1.0 - 3.0.0.Final + 1.2.0 + 6.0.23 1.4 2.5 - - 2.1.547 + 3.2.0-37 1.0.1 1.2.0 7.0.50 1.2.0 1.2.0 1.13 - 4.2.5 - 2.1 + 4.5.2 + 4.1.3 + 2.3.1 1.4.2 2.7.2 3.2.2 - 2.0 + 2.9.7 4.3 - 4.10 + 4.11 1.9.1 - 1.8.0.10 - - 1.2.222 + 2.3.2 + 1.2.293 1.0.3.Final - 1.0.0-CR1 - 1.0.0-CR1 + 1.0.3 + 1.0.2 2.0.0-alpha-4 - 2.0.0 + 2.0.4 - 7.0.50 + 7.0.64 1.0.0.FINAL 2.9.1 1.0.0-ALPHA2 + 1.11.179 + + 5.0.8 + 6.0.2 + 3.0.0 + 3.0.2 + 3.9.6.Final + 1.1.3 + 3.1.0 + 7.1.0-79 + 2.8.9 + + @@ -123,8 +146,12 @@ restcomm.commons restcomm.dao restcomm.asr + restcomm.tts.acapela restcomm.mgcp restcomm.fax + restcomm.mscontrol.api + restcomm.mscontrol.mms + restcomm.mscontrol.jsr309 restcomm.sms.api restcomm.telephony.api restcomm.interpreter @@ -133,17 +160,64 @@ restcomm.provisioning.number.api restcomm.provisioning.number.vi restcomm.provisioning.number.nexmo + restcomm.provisioning.number.bandwidth + restcomm.provisioning.number.voxbone restcomm.telephony restcomm.tts.api restcomm.tts.voicerss restcomm.testsuite - restcomm.ussd restcomm.ui - restcomm.rvd - + restcomm.tts.att + restcomm.ussd + restcomm.routing + restcomm.email + restcomm.email.api + restcomm.extension.api + restcomm.extension.controller + restcomm.identity + restcomm.mrb + restcomm.mrb.api + restcomm.dns.api + restcomm.monitoring.service + restcomm.tts.awspolly + restcomm.sdr.api + + + + + org.restcomm + restcomm-connect.sms.api + ${project.version} + + + junit + junit + ${junit.version} + + + + com.cloudhopper + ch-commons-gsm + ${ch.commons.gsm.version} + + + + com.cloudhopper + ch-smpp + ${ch.smpp.version} + com.google.guava @@ -190,6 +264,18 @@ ${commons-io.version} + + commons-codec + commons-codec + ${commons-codec.version} + + + + commons-lang + commons-lang + ${commons-lang.version} + + org.slf4j slf4j-api @@ -202,12 +288,6 @@ ${slf4j.version} - - javax.sdp - nist-sdp - ${jain.sdp.version} - - jain jain-mgcp-ri @@ -239,7 +319,7 @@ provided - @@ -266,6 +346,12 @@ ${jersey.version} + + com.sun.jersey + jersey-json + ${jersey.version} + + stax stax-api @@ -286,6 +372,12 @@ ${httpclient.version} + + org.apache.httpcomponents + httpasyncclient + ${httpasyncclient.version} + + com.google.code.gson gson @@ -372,13 +464,6 @@ provided - - org.mobicents.servlet.sip.containers - sip-servlets-tomcat-7 - ${sipservletapi.version} - provided - - org.mobicents.servlet.sip sip-servlets-application-router @@ -387,10 +472,9 @@ - hsqldb + org.hsqldb hsqldb ${hsqldb.version} - test @@ -403,6 +487,10 @@ com.telscale.licensing lce-core + + org.mobicents.sipunit + * + @@ -428,7 +516,7 @@ - org.cafesip.sipunit + org.mobicents.sipunit sipunit ${sipunit.version} test @@ -444,6 +532,31 @@ naturalvoices 5.1 + + + com.amazonaws + aws-java-sdk-s3 + ${aws.sdk.version} + + + + org.apache.maven + maven-artifact + ${maven-artifact.version} + + + + org.restcomm.smpp + smpp-extensions + ${smpp-extensions.version} + + + + org.mockito + mockito-core + ${mockito-core.version} + test + @@ -474,14 +587,14 @@ org.apache.tomcat tomcat-coyote ${tomcat7.version} - provided + test org.apache.tomcat tomcat-jasper ${tomcat7.version} - provided + test @@ -495,71 +608,55 @@ org.mobicents.servlet.sip.containers sip-servlets-catalina-7 ${sipservletapi.version} - provided - - - - org.mobicents.servlet.sip.containers - sip-servlets-tomcat-7 - ${sipservletapi.version} - provided + test org.mobicents.servlet.sip sip-servlets-application-router ${sipservletapi.version} - provided + test - hsqldb + org.hsqldb hsqldb ${hsqldb.version} - test + test - org.mobicents.arquillian.container - mss-tomcat-embedded-7 - ${mss.arquillian.version} + org.mobicents.sipunit + sipunit + ${sipunit.version} test - - org.jboss.arquillian.junit - arquillian-junit-container - ${arquillian.version} - test + org.mobicents + checkstyle + ${mobicents.checkstyle.version} - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-impl-maven - ${shrinkwrap.resolver.version} - test + commons-codec + commons-codec + ${commons-codec.version} - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-impl-maven-archive - ${shrinkwrap.resolver.version} - test + commons-lang + commons-lang + ${commons-lang.version} - org.cafesip.sipunit - sipunit - ${sipunit.version} + org.mockito + mockito-core + ${mockito-core.version} test - - org.mobicents - checkstyle - ${mobicents.checkstyle.version} - - @@ -570,7 +667,7 @@ maven-compiler-plugin - + 1.7 1.7 @@ -584,6 +681,15 @@ true + + + org.apache.maven.plugins + maven-surefire-plugin + + + @{jacocoArgLine} + + org.apache.maven.plugins @@ -593,7 +699,7 @@ /checkstyle/checkstyle.xml true true - + @@ -612,6 +718,52 @@ + + + org.codehaus.mojo + license-maven-plugin + 1.13 + + + org.jacoco + jacoco-maven-plugin + 0.7.9 + + + + pre-unit-test + + prepare-agent + + + + jacocoArgLine + true + + + + + post-unit-test + test + + report + + + + ${project.reporting.outputDirectory}/jacoco-ut + + + + @@ -757,7 +909,7 @@ - diff --git a/restcomm/restcomm.application/pom.xml b/restcomm/restcomm.application/pom.xml index 9f1b58164d..c3596cd052 100644 --- a/restcomm/restcomm.application/pom.xml +++ b/restcomm/restcomm.application/pom.xml @@ -2,14 +2,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.application + restcomm-connect.application war - restcomm.application + restcomm-connect.application http://maven.apache.org @@ -57,13 +57,6 @@ commons-configuration - - commons-lang - commons-lang - 2.6 - - - javax.mail mail @@ -72,9 +65,14 @@ org.mobicents.servlet.sip sip-servlets-spec - ${sipservletapi.version} provided + + + org.mobicents.servlet.sip.containers + sip-servlets-catalina-7 + provided + javax.servlet @@ -83,104 +81,201 @@ - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons + ${project.version} + + + + org.restcomm + restcomm-connect.dao + ${project.version} + + + + org.restcomm + restcomm-connect.asr + ${project.version} + + + + org.restcomm + restcomm-connect.fax + ${project.version} + + + + org.restcomm + restcomm-connect.http + ${project.version} + + + + org.restcomm + restcomm-connect.interpreter + ${project.version} + + + + org.restcomm + restcomm-connect.mgcp + ${project.version} + + + + org.restcomm + restcomm-connect.sms + ${project.version} + + + + org.restcomm + restcomm-connect.sms.api + ${project.version} + + + + org.restcomm + restcomm-connect.provisioning.number.api + ${project.version} + + + + org.restcomm + restcomm-connect.provisioning.number.vi + ${project.version} + + + + org.restcomm + restcomm-connect.provisioning.number.nexmo + ${project.version} + + + + org.restcomm + restcomm-connect.provisioning.number.bandwidth + ${project.version} + + + + org.restcomm + restcomm-connect.provisioning.number.voxbone + ${project.version} + + + + org.restcomm + restcomm-connect.telephony + ${project.version} + + + + org.restcomm + restcomm-connect.telephony.api ${project.version} - com.telestax.servlet - restcomm.dao + org.restcomm + restcomm-connect.tts.acapela ${project.version} - com.telestax.servlet - restcomm.asr + org.restcomm + restcomm-connect.tts.voicerss ${project.version} - com.telestax.servlet - restcomm.fax + org.restcomm + restcomm-connect.tts.att ${project.version} - com.telestax.servlet - restcomm.http + org.restcomm + restcomm-connect.tts.awspolly + ${project.version} + + + + org.restcomm + restcomm-connect.tts.api ${project.version} - com.telestax.servlet - restcomm.interpreter + org.restcomm + restcomm-connect.ussd ${project.version} - com.telestax.servlet - restcomm.mgcp + org.restcomm + restcomm-connect.mscontrol.api ${project.version} - com.telestax.servlet - restcomm.sms + org.restcomm + restcomm-connect.mscontrol.mms ${project.version} - com.telestax.servlet - restcomm.sms.api + org.restcomm + restcomm-connect.mscontrol.jsr309 ${project.version} - com.telestax.servlet - restcomm.provisioning.number.api + org.restcomm + restcomm-connect.identity ${project.version} - com.telestax.servlet - restcomm.provisioning.number.vi + org.restcomm + restcomm-connect.monitoring.service ${project.version} - com.telestax.servlet - restcomm.provisioning.number.nexmo + org.restcomm + restcomm-connect.extension.controller ${project.version} - com.telestax.servlet - restcomm.telephony + org.restcomm + restcomm-connect.extension.api ${project.version} - com.telestax.servlet - restcomm.telephony.api + org.restcomm + restcomm-connect.mrb ${project.version} - com.telestax.servlet - restcomm.tts.voicerss + org.restcomm + restcomm-connect.mrb.api ${project.version} + - com.telestax.servlet - restcomm.tts.api + org.restcomm + restcomm-connect.dns.api ${project.version} - com.telestax.servlet - restcomm.ussd + org.restcomm + restcomm-connect.sdr.api ${project.version} @@ -194,8 +289,6 @@ org.hsqldb hsqldb - 1.8.0.10 - provided diff --git a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Bootstrapper.java b/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Bootstrapper.java deleted file mode 100644 index ace240d283..0000000000 --- a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Bootstrapper.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.mobicents.servlet.restcomm; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.sip.SipServlet; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.commons.configuration.interpol.ConfigurationInterpolator; -import org.apache.log4j.Logger; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.shiro.ShiroResources; -import org.mobicents.servlet.restcomm.loader.ObjectFactory; -import org.mobicents.servlet.restcomm.loader.ObjectInstantiationException; -import org.mobicents.servlet.restcomm.mgcp.MediaGateway; -import org.mobicents.servlet.restcomm.mgcp.PowerOnMediaGateway; -import org.mobicents.servlet.restcomm.telephony.config.ConfigurationStringLookup; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; - -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; - -public final class Bootstrapper extends SipServlet { - private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(Bootstrapper.class); - - private ActorSystem system; - - public Bootstrapper() { - super(); - } - - @Override - public void destroy() { - system.shutdown(); - system.awaitTermination(); - } - - private ActorRef gateway(final Configuration configuration, final ClassLoader loader) throws UnknownHostException { - final Configuration settings = configuration.subset("media-server-manager"); - final ActorRef gateway = system.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - final String classpath = settings.getString("mgcp-server[@class]"); - return (UntypedActor) new ObjectFactory(loader).getObjectInstance(classpath); - } - })); - final PowerOnMediaGateway.Builder builder = PowerOnMediaGateway.builder(); - builder.setName(settings.getString("mgcp-server[@name]")); - String address = settings.getString("mgcp-server.local-address"); - builder.setLocalIP(InetAddress.getByName(address)); - String port = settings.getString("mgcp-server.local-port"); - builder.setLocalPort(Integer.parseInt(port)); - address = settings.getString("mgcp-server.remote-address"); - builder.setRemoteIP(InetAddress.getByName(address)); - port = settings.getString("mgcp-server.remote-port"); - builder.setRemotePort(Integer.parseInt(port)); - address = settings.getString("mgcp-server.external-address"); - if (address != null) { - builder.setExternalIP(InetAddress.getByName(address)); - builder.setUseNat(true); - } else { - builder.setUseNat(false); - } - final String timeout = settings.getString("mgcp-server.response-timeout"); - builder.setTimeout(Long.parseLong(timeout)); - final PowerOnMediaGateway powerOn = builder.build(); - gateway.tell(powerOn, null); - return gateway; - } - - private String home(final ServletConfig config) { - final ServletContext context = config.getServletContext(); - final String path = context.getRealPath("/"); - if (path.endsWith("/")) { - return path.substring(0, path.length() - 1); - } else { - return path; - } - } - - @Override - public void init(final ServletConfig config) throws ServletException { - final ServletContext context = config.getServletContext(); - final String path = context.getRealPath("WEB-INF/conf/restcomm.xml"); - // Initialize the configuration interpolator. - final ConfigurationStringLookup strings = new ConfigurationStringLookup(); - strings.addProperty("home", home(config)); - strings.addProperty("uri", uri(config)); - ConfigurationInterpolator.registerGlobalLookup("restcomm", strings); - // Load the RestComm configuration file. - Configuration xml = null; - try { - xml = new XMLConfiguration(path); - } catch (final ConfigurationException exception) { - logger.error(exception); - } - xml.setProperty("runtime-settings.home-directory", home(config)); - xml.setProperty("runtime-settings.root-uri", uri(config)); - context.setAttribute(Configuration.class.getName(), xml); - // Initialize global dependencies. - final ClassLoader loader = getClass().getClassLoader(); - // Create the actor system. - final Config settings = ConfigFactory.load(); - system = ActorSystem.create("RestComm", settings, loader); - // Share the actor system with other servlets. - context.setAttribute(ActorSystem.class.getName(), system); - // Create the storage system. - DaoManager storage = null; - try { - storage = storage(xml, loader); - } catch (final ObjectInstantiationException exception) { - throw new ServletException(exception); - } - context.setAttribute(DaoManager.class.getName(), storage); - ShiroResources.getInstance().set(DaoManager.class, storage); - ShiroResources.getInstance().set(Configuration.class, xml.subset("runtime-settings")); - // Create the media gateway. - ActorRef gateway = null; - try { - gateway = gateway(xml, loader); - } catch (final UnknownHostException exception) { - throw new ServletException(exception); - } - context.setAttribute(MediaGateway.class.getName(), gateway); - Version.printVersion(); - Ping ping = new Ping(xml, context); - ping.sendPing(); - } - - - private DaoManager storage(final Configuration configuration, final ClassLoader loader) throws ObjectInstantiationException { - final String classpath = configuration.getString("dao-manager[@class]"); - final DaoManager daoManager = (DaoManager) new ObjectFactory(loader).getObjectInstance(classpath); - daoManager.configure(configuration.subset("dao-manager")); - daoManager.start(); - return daoManager; - } - - private String uri(final ServletConfig config) { - return config.getServletContext().getContextPath(); - } -} 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 new file mode 100644 index 0000000000..9730af997f --- /dev/null +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Bootstrapper.java @@ -0,0 +1,515 @@ +package org.restcomm.connect.application; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import javax.media.mscontrol.MsControlException; +import javax.media.mscontrol.MsControlFactory; +import javax.media.mscontrol.spi.Driver; +import javax.media.mscontrol.spi.DriverManager; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.sip.SipServlet; +import javax.servlet.sip.SipServletContextEvent; +import javax.servlet.sip.SipServletListener; +import javax.servlet.sip.SipURI; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.configuration.interpol.ConfigurationInterpolator; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.mobicents.servlet.sip.SipConnector; +import org.restcomm.connect.application.config.ConfigurationStringLookup; +import org.restcomm.connect.commons.Version; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.loader.ObjectFactory; +import org.restcomm.connect.commons.loader.ObjectInstantiationException; +import org.restcomm.connect.commons.util.DNSUtils; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.InstanceId; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.Profile; +import org.restcomm.connect.dao.entities.shiro.ShiroResources; +import org.restcomm.connect.extension.controller.ExtensionBootstrapper; +import org.restcomm.connect.identity.IdentityContext; +import org.restcomm.connect.interpreter.NumberSelectorService; +import org.restcomm.connect.monitoringservice.MonitoringService; +import org.restcomm.connect.mrb.api.StartMediaResourceBroker; +import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; +import org.restcomm.connect.mscontrol.api.MediaServerInfo; +import org.restcomm.connect.mscontrol.jsr309.Jsr309ControllerFactory; +import org.restcomm.connect.mscontrol.mms.MmsControllerFactory; +import org.restcomm.connect.sdr.api.StartSdrService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; + +import akka.actor.Actor; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActor; +import akka.actor.UntypedActorFactory; +import static org.restcomm.connect.dao.entities.Profile.DEFAULT_PROFILE_SID; +import scala.concurrent.ExecutionContext; + +/** + * @author gvagenas + * @author maria-farooq@live.com (Maria Farooq) + */ + +public final class Bootstrapper extends SipServlet implements SipServletListener { + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(Bootstrapper.class); + + private ActorSystem system; + private ExecutionContext ec; + + public Bootstrapper() { + super(); + } + + @Override + public void destroy() { + CustomHttpClientBuilder.stopDefaultClient(); + system.shutdown(); + system.awaitTermination(); + } + + private MediaServerControllerFactory mediaServerControllerFactory(final Configuration configuration, ClassLoader loader, DaoManager storage, ActorRef monitoring) + throws ServletException { + Configuration settings; + String compatibility = configuration.subset("mscontrol").getString("compatibility", "rms"); + + MediaServerControllerFactory factory; + switch (compatibility) { + case "rms": + try { + settings = configuration.subset("media-server-manager"); + ActorRef mrb = mediaResourceBroker(settings, storage, loader, monitoring); + factory = new MmsControllerFactory(mrb); + } catch (UnknownHostException e) { + throw new ServletException(e); + } + break; + + case "xms": + try { + settings = configuration.subset("mscontrol"); + // Load JSR 309 driver + final String driverName = settings.getString("media-server[@class]"); + Driver driver = DriverManager.getDriver(driverName); + DriverManager.registerDriver(driver); + + // Configure properties + Properties properties = getDialogicXmsProperties(settings); + + // Create JSR 309 factory + MsControlFactory msControlFactory = driver.getFactory(properties); + MediaServerInfo mediaServerInfo = mediaServerInfo(settings); + factory = new Jsr309ControllerFactory(mediaServerInfo, msControlFactory); + } catch (UnknownHostException | MsControlException e) { + throw new ServletException(e); + } + break; + + default: + throw new IllegalArgumentException("MSControl unknown compatibility mode: " + compatibility); + } + return factory; + } + + private MediaServerInfo mediaServerInfo(final Configuration configuration) throws UnknownHostException { + final String name = configuration.getString("media-server[@name]"); + final String address = configuration.getString("media-server.address"); + final int port = configuration.getInt("media-server.port"); + final int timeout = configuration.getInt("media-server.timeout", 5); + return new MediaServerInfo(name, DNSUtils.getByName(address), port, timeout); + } + + private Properties getDialogicXmsProperties(final Configuration configuration) { + // New set of properties that will be used to configure the connector + Properties properties = new Properties(); + + // Tell the driver we are configuring it programmatically + // properties.setProperty("connector.dynamic.configuration", "yes"); + + // Configure the transport to be used by the connector + final String mediaTransport = configuration.getString("media-server.transport", "udp"); + if (logger.isInfoEnabled()) { + logger.info("JSR 309 - media-server.transport: udp"); + } + properties.setProperty("connector.sip.transport", mediaTransport); + + // Configure SIP connector using RestComm binding address + SipURI sipURI = outboundInterface(getServletContext(), mediaTransport); + properties.setProperty("connector.sip.address", sipURI.getHost()); + if (logger.isInfoEnabled()) { + logger.info("JSR 309 - connector.sip.address: " + sipURI.getHost()); + } + properties.setProperty("connector.sip.port", String.valueOf(sipURI.getPort())); + if (logger.isInfoEnabled()) { + logger.info("JSR 309 - connector.sip.port: " + String.valueOf(sipURI.getPort())); + } + + // Configure Media Server address based on restcomm configuration file + final String mediaAddress = configuration.getString("media-server.address", "127.0.0.1"); + properties.setProperty("mediaserver.sip.ipaddress", mediaAddress); + if (logger.isInfoEnabled()) { + logger.info("JSR 309 - mediaserver.sip.ipaddress: " + mediaAddress); + } + + final String mediaPort = configuration.getString("media-server.port", "5060"); + properties.setProperty("mediaserver.sip.port", mediaPort); + if (logger.isInfoEnabled()) { + logger.info("JSR 309 - mediaserver.sip.port: " + mediaPort); + } + + // Let RestComm control call legs + properties.setProperty("connector.conferenceControlLeg", "no"); + + return properties; + } + + @SuppressWarnings("unchecked") + private SipURI outboundInterface(ServletContext context, String transport) { + SipURI result = null; + final List uris = (List) context.getAttribute(OUTBOUND_INTERFACES); + if (uris != null && uris.size() > 0) { + for (final SipURI uri : uris) { + final String interfaceTransport = uri.getTransportParam(); + if (transport.equalsIgnoreCase(interfaceTransport)) { + result = uri; + } + } + if (logger.isInfoEnabled()) { + if (result == null) { + logger.info("Outbound interface is NULL! Looks like there was no " + transport + " in the list of connectors"); + } else { + logger.info("Outbound interface found: " + result.toString()); + } + } + } else { + if (logger.isInfoEnabled()) { + logger.info("ServletContext return null or empty list of connectors"); + } + } + return result; + } + + private ActorRef mediaResourceBroker(final Configuration configuration, final DaoManager storage, final ClassLoader loader, final ActorRef monitoring) throws UnknownHostException { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + final String classpath = configuration.getString("mrb[@class]"); + return (UntypedActor) new ObjectFactory(loader).getObjectInstance(classpath); + } + }); + ActorRef mrb = system.actorOf(props); + mrb.tell(new StartMediaResourceBroker(configuration, storage, loader, monitoring), null); + return mrb; + } + + private String home(final ServletContext context) { + final String path = context.getRealPath("/"); + if (path.endsWith("/")) { + return path.substring(0, path.length() - 1); + } else { + return path; + } + } + + private DaoManager storage(final Configuration configuration, Configuration daoManagerConfiguration, final ClassLoader loader, final ExecutionContext ec) throws ObjectInstantiationException { + final String classpath = daoManagerConfiguration.getString("dao-manager[@class]"); + final DaoManager daoManager = (DaoManager) new ObjectFactory(loader).getObjectInstance(classpath); + daoManager.configure(configuration, daoManagerConfiguration, ec); + daoManager.start(); + return daoManager; + } + + private ActorRef monitoringService(final Configuration configuration, final DaoManager daoManager, final ClassLoader loader) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new MonitoringService(daoManager); + } + }); + return system.actorOf(props); + + } + + private ActorRef sdrService(final Configuration configuration, final ClassLoader loader) throws Exception { + final String className = configuration.subset("runtime-settings").getString("sdr-service[@class]"); + if (className != null) { + final Props props = new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return (Actor) new ObjectFactory(loader).getObjectInstance(className); + } + }); + ActorRef sdr = system.actorOf(props); + sdr.tell(new StartSdrService(configuration), null); + return sdr; + } + return null; + } + + private String uri(final ServletContext context) { + return context.getContextPath(); + } + + /** + * generateDefaultDomainName based on RC hostname + * https://github.com/RestComm/Restcomm-Connect/issues/2085 + * + * @param configuration + * @param storage + * @param sipUriHostAsFallbackDomain - if hostname is not provided in restcomm.xml then provided sipuri host will be used as domain. + */ + private boolean generateDefaultDomainName(final Configuration configuration, final DaoManager storage, final SipURI sipUriHostAsFallbackDomain) { + try { + final Sid defaultOrganization = new Sid("ORafbe225ad37541eba518a74248f0ac4c"); + String hostname = configuration.getString("hostname"); + + if (hostname != null && !hostname.trim().equals("")) { + if (logger.isInfoEnabled()) + logger.info("Generate Default Domain Name based on RC hostname: " + hostname); + } else { + if (sipUriHostAsFallbackDomain != null) { + logger.warn("Hostname property is null in restcomm.xml, will assign this host as domain: " + sipUriHostAsFallbackDomain.getHost()); + hostname = sipUriHostAsFallbackDomain.getHost(); + } else { + logger.error("Hostname property is null in restcomm.xml, As well restcomm outbound sipuri is NULL."); + return false; + } + } + + Organization organization = storage.getOrganizationsDao().getOrganization(defaultOrganization); + if (organization == null) { + storage.getOrganizationsDao().addOrganization(new Organization(defaultOrganization, hostname, DateTime.now(), DateTime.now(), Organization.Status.ACTIVE)); + } else { + organization = organization.setDomainName(hostname); + storage.getOrganizationsDao().updateOrganization(organization); + } + } catch (Exception e) { + logger.error("Unable to generateDefaultDomainName {}", e); + return false; + } + return true; + } + + /** + * generateDefaultProfile if does not already exists + * @throws SQLException + * @throws IOException + */ + private void generateDefaultProfile(final DaoManager storage, final String profileSourcePath) throws SQLException, IOException{ + Profile profile = storage.getProfilesDao().getProfile(DEFAULT_PROFILE_SID); + + if (profile == null) { + if(logger.isDebugEnabled()) { + logger.debug("default profile does not exist, will create one from default Plan"); + } + JsonNode jsonNode = JsonLoader.fromPath(profileSourcePath); + profile = new Profile(DEFAULT_PROFILE_SID, jsonNode.toString(), new Date(), new Date()); + storage.getProfilesDao().addProfile(profile); + } else { + if(logger.isDebugEnabled()){ + logger.debug("default profile already exists, will not override it."); + } + } + } + + @Override + public void servletInitialized(SipServletContextEvent event) { + if (event.getSipServlet().getClass().equals(Bootstrapper.class)) { + final ServletContext context = event.getServletContext(); + final String path = context.getRealPath("WEB-INF/conf/restcomm.xml"); + final String extensionConfigurationPath = context.getRealPath("WEB-INF/conf/extensions.xml"); + final String daoManagerConfigurationPath = context.getRealPath("WEB-INF/conf/dao-manager.xml"); + // Initialize the configuration interpolator. + final ConfigurationStringLookup strings = new ConfigurationStringLookup(); + strings.addProperty("home", home(context)); + strings.addProperty("uri", uri(context)); + ConfigurationInterpolator.registerGlobalLookup("restcomm", strings); + // Load the RestComm configuration file. + Configuration xml = null; + XMLConfiguration extensionConf = null; + XMLConfiguration daoManagerConf = null; + try { + XMLConfiguration xmlConfiguration = new XMLConfiguration(); + xmlConfiguration.setDelimiterParsingDisabled(true); + xmlConfiguration.setAttributeSplittingDisabled(true); + xmlConfiguration.load(path); + xml = xmlConfiguration; + + extensionConf = new XMLConfiguration(); + extensionConf.setDelimiterParsingDisabled(true); + extensionConf.setAttributeSplittingDisabled(true); + extensionConf.load(extensionConfigurationPath); + + daoManagerConf = new XMLConfiguration(); + daoManagerConf.setDelimiterParsingDisabled(true); + daoManagerConf.setAttributeSplittingDisabled(true); + daoManagerConf.load(daoManagerConfigurationPath); + + } catch (final ConfigurationException exception) { + logger.error(exception); + } + xml.setProperty("runtime-settings.home-directory", home(context)); + xml.setProperty("runtime-settings.root-uri", uri(context)); + // initialize DnsUtilImpl ClassName + DNSUtils.initializeDnsUtilImplClassName(xml); + // Create high-level restcomm configuration + RestcommConfiguration.createOnce(xml); + context.setAttribute(Configuration.class.getName(), xml); + context.setAttribute("ExtensionConfiguration", extensionConf); + // Initialize global dependencies. + final ClassLoader loader = getClass().getClassLoader(); + // Create the actor system. + final Config settings = ConfigFactory.load(); + system = ActorSystem.create("RestComm", settings, loader); + // Share the actor system with other servlets. + context.setAttribute(ActorSystem.class.getName(), system); + ec = system.dispatchers().lookup("restcomm-blocking-dispatcher"); + // Create the storage system. + DaoManager storage = null; + try { + storage = storage(xml, daoManagerConf, loader, ec); + } catch (final ObjectInstantiationException exception) { + logger.error("ObjectInstantiationException during initialization: ", exception); + } + context.setAttribute(DaoManager.class.getName(), storage); + //ShiroResources.getInstance().set(DaoManager.class, storage); + ShiroResources.getInstance().set(Configuration.class, xml.subset("runtime-settings")); + // Initialize identityContext + IdentityContext identityContext = new IdentityContext(xml); + context.setAttribute(IdentityContext.class.getName(), identityContext); + + //init NumberSelectorService + context.setAttribute(NumberSelectorService.class.getName(), new NumberSelectorService(storage.getIncomingPhoneNumbersDao())); + + // Create the media gateway. + + //Initialize Monitoring Service + ActorRef monitoring = monitoringService(xml, storage, loader); + if (monitoring != null) { + context.setAttribute(MonitoringService.class.getName(), monitoring); + if (logger.isInfoEnabled()) { + logger.info("Monitoring Service created and stored in the context"); + } + } else { + logger.error("Monitoring Service is null"); + } + + //Initialize Sdr Service + try { + sdrService(xml, loader); + } catch (Exception e) { + logger.error("Exception during Sdr Service initialization: " + e.getStackTrace()); + } + + CloseableHttpClient buildDefaultClient = CustomHttpClientBuilder.buildDefaultClient(RestcommConfiguration.getInstance().getMain()); + context.setAttribute(CustomHttpClientBuilder.class.getName(), buildDefaultClient); + + //Initialize Extensions + Configuration extensionConfiguration = null; + try { + extensionConfiguration = new XMLConfiguration(extensionConfigurationPath); + } catch (final ConfigurationException exception) { +// logger.error(exception); + } + + ExtensionBootstrapper extensionBootstrapper = new ExtensionBootstrapper(context, extensionConfiguration); + try { + extensionBootstrapper.start(); + } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) { + logger.error("Exception during extension scanner start: " + e.getStackTrace()); + } + + try { + generateDefaultProfile(storage, context.getRealPath("WEB-INF/conf/defaultPlan.json")); + } catch (SQLException | IOException e1) { + logger.error("Exception during generateDefaultProfile: ", e1); + } + + // Create the media server controller factory + MediaServerControllerFactory mscontrollerFactory = null; + try { + mscontrollerFactory = mediaServerControllerFactory(xml, loader, storage, monitoring); + } catch (ServletException exception) { + logger.error("ServletException during initialization: ", exception); + } + context.setAttribute(MediaServerControllerFactory.class.getName(), mscontrollerFactory); + + Boolean rvdMigrationEnabled = new Boolean(xml.subset("runtime-settings").getString("rvd-workspace-migration-enabled", "false")); + if (rvdMigrationEnabled) { + //Replicate RVD Projects as database entities + try { + RvdProjectsMigrator rvdProjectMigrator = new RvdProjectsMigrator(context, xml); + rvdProjectMigrator.executeMigration(); + } catch (Exception exception) { + logger.error("RVD Porjects migration failed during initialization: ", exception); + } + } + + //Last, print Version and send PING if needed + Version.printVersion(); + GenerateInstanceId generateInstanceId = null; + InstanceId instanceId = null; + SipURI sipURI = null; + try { + sipURI = outboundInterface(context, "udp"); + if (sipURI != null) { + generateInstanceId = new GenerateInstanceId(context, sipURI); + } else { + if (logger.isInfoEnabled()) { + logger.info("SipURI is NULL!!! Cannot proceed to generate InstanceId"); + } + } + instanceId = generateInstanceId.instanceId(); + } catch (UnknownHostException e) { + logger.error("UnknownHostException during the generation of InstanceId: " + e); + } + + context.setAttribute(InstanceId.class.getName(), instanceId); + monitoring.tell(instanceId, null); + RestcommConfiguration.getInstance().getMain().setInstanceId(instanceId.getId().toString()); + + if (!generateDefaultDomainName(xml.subset("http-client"), storage, sipURI)) { + logger.error("Unable to generate DefaultDomainName, Restcomm Akka system will exit now..."); + system.shutdown(); + system.awaitTermination(); + } + + // https://github.com/RestComm/Restcomm-Connect/issues/1285 Pass InstanceId to the Load Balancer for LCM stickiness + SipConnector[] connectors = (SipConnector[]) context.getAttribute("org.mobicents.servlet.sip.SIP_CONNECTORS"); + Properties loadBalancerCustomInfo = new Properties(); + loadBalancerCustomInfo.setProperty("Restcomm-Instance-Id", instanceId.getId().toString()); + for (SipConnector sipConnector : connectors) { + if (logger.isDebugEnabled()) { + logger.debug("Passing InstanceId " + instanceId.getId().toString() + " to connector " + sipConnector); + } + sipConnector.setLoadBalancerCustomInformation(loadBalancerCustomInfo); + } + //Depreciated +// Ping ping = new Ping(xml, context); +// ping.sendPing(); + } + } +} diff --git a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/GenerateInstanceId.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/GenerateInstanceId.java new file mode 100644 index 0000000000..2dfca608f6 --- /dev/null +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/GenerateInstanceId.java @@ -0,0 +1,70 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.application; + +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.InstanceIdDao; +import org.restcomm.connect.dao.entities.InstanceId; +import org.restcomm.connect.commons.dao.Sid; + +import javax.servlet.ServletContext; +import javax.servlet.sip.SipURI; +import java.net.UnknownHostException; + +/** + * @author gvagenas + * + */ +public class GenerateInstanceId { + + private final Logger logger = Logger.getLogger(GenerateInstanceId.class); + +// private final Configuration configuration; + private final ServletContext servletContext; + private final InstanceIdDao instanceIdDao; + private final String host; + + public GenerateInstanceId(ServletContext servletContext, final SipURI sipURI) throws UnknownHostException { + this.servletContext = servletContext; + host = sipURI.getHost()+":"+sipURI.getPort(); + logger.info("Host for InstanceId: "+host); + instanceIdDao = ((DaoManager) servletContext.getAttribute(DaoManager.class.getName())).getInstanceIdDao(); + } + + public InstanceId instanceId() { + InstanceId instanceId = instanceIdDao.getInstanceIdByHost(host); + if (instanceId != null) { + if(logger.isInfoEnabled()) { + logger.info("Restcomm Instance ID: "+instanceId.toString()); + } + } else { + instanceId = new InstanceId(Sid.generate(Sid.Type.INSTANCE), host, DateTime.now(), DateTime.now()); + instanceIdDao.addInstancecId(instanceId); + if(logger.isInfoEnabled()) { + logger.info("Restcomm Instance ID created: "+instanceId.toString()); + } + } + servletContext.setAttribute(InstanceId.class.getName(), instanceId); + return instanceId; + } +} diff --git a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Ping.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Ping.java similarity index 76% rename from restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Ping.java rename to restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Ping.java index 185f55cb5a..0f0ba7696f 100644 --- a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/Ping.java +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Ping.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm; +package org.restcomm.connect.application; import java.util.ArrayList; import java.util.List; @@ -33,32 +33,41 @@ import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.log4j.Logger; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.provisioning.number.api.ProvisionProvider; /** * @author gvagenas * */ +@Deprecated public class Ping { private Logger logger = Logger.getLogger(Ping.class); private Configuration configuration; private ServletContext context; private Timer timer; + private Timer subsequentTimer; + private boolean subsequentTimerIsSet = false; + private PingTask ping; + private final String provider; Ping(Configuration configuration, ServletContext context){ this.configuration = configuration; this.context = context; + this.provider = configuration.getString("phone-number-provisioning[@class]"); } public void sendPing(){ boolean daemon = true; timer = new Timer(daemon); - PingTask ping = new PingTask(configuration); + ping = new PingTask(configuration); timer.schedule(ping, 0, 60000); } @@ -73,6 +82,8 @@ public PingTask(Configuration configuration) { public void run() { Configuration proxyConf = configuration.subset("runtime-settings").subset("telestax-proxy"); Boolean proxyEnabled = proxyConf.getBoolean("enabled"); + Configuration mediaConf = configuration.subset("media-server-manager").subset("mgcp-server"); + String publicIpAddress = mediaConf.getString("external-address"); if (proxyEnabled) { String proxyUri = proxyConf.getString("uri"); String username = proxyConf.getString("login"); @@ -86,6 +97,7 @@ public void run() { buffer.append("").append("ping").append(""); buffer.append(""); buffer.append("").append(endpoint).append(""); +// buffer.append("").append(provider).append(""); buffer.append(""); buffer.append(""); buffer.append(""); @@ -95,22 +107,33 @@ public void run() { List parameters = new ArrayList(); parameters.add(new BasicNameValuePair("apidata", body)); post.setEntity(new UrlEncodedFormEntity(parameters)); - final DefaultHttpClient client = new DefaultHttpClient(); + final HttpClient client = CustomHttpClientBuilder.build(RestcommConfiguration.getInstance().getMain()); //This will work as a flag for LB that this request will need to be modified and proxied to VI post.addHeader("TelestaxProxy", String.valueOf(proxyEnabled)); + //Adds the Provision provider class name + post.addHeader("Provider", provider); //This will tell LB that this request is a getAvailablePhoneNumberByAreaCode request - post.addHeader("RequestType", "Ping"); + post.addHeader("RequestType", ProvisionProvider.REQUEST_TYPE.PING.name()); //This will let LB match the DID to a node based on the node host+port List uris = outboundInterface(); for (SipURI uri: uris) { post.addHeader("OutboundIntf", uri.getHost()+":"+uri.getPort()+":"+uri.getTransportParam()); } - + if (publicIpAddress != null || !publicIpAddress.equalsIgnoreCase("")) { + post.addHeader("PublicIpAddress",publicIpAddress); + } final HttpResponse response = client.execute(post); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { logger.info("Ping to Telestax Proxy was successfully sent"); timer.cancel(); +// if (!subsequentTimerIsSet) { +// logger.info("Will set subsequent timer"); +// boolean daemon = true; +// subsequentTimer = new Timer(daemon); +// subsequentTimer.schedule(ping, 1800000, 1800000); +// subsequentTimerIsSet = true; +// } return; } else { logger.error("Ping to Telestax Proxy was sent, but there was a problem. Response status line: "+response.getStatusLine()); diff --git a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationException.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationException.java new file mode 100644 index 0000000000..44d7847847 --- /dev/null +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationException.java @@ -0,0 +1,64 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.application; + +/** + * @author guilherme.jansen@telestax.com + */ +public class RvdProjectsMigrationException extends Exception { + + private String message; + private int errorCode; + + public RvdProjectsMigrationException(String message, int errorCode) { + super(); + this.message = message; + this.errorCode = errorCode; + } + + public RvdProjectsMigrationException(String message) { + super(); + this.message = message; + } + + public RvdProjectsMigrationException() { + + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + +} diff --git a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationHelper.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationHelper.java new file mode 100644 index 0000000000..8a9a13e6db --- /dev/null +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrationHelper.java @@ -0,0 +1,684 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.application; + +import akka.actor.Actor; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActorFactory; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.FileUtils; +import org.apache.ibatis.exceptions.TooManyResultsException; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.util.StringUtils; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.email.EmailService; +import org.restcomm.connect.email.api.EmailRequest; +import org.restcomm.connect.email.api.Mail; + +import javax.servlet.ServletContext; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; + +/** + * This class was designed to be used with exclusivity by {@link RvdProjectsMigrator}, once that + * Restcomm should not interact with RVD's workspace as a typical operation given that the migration process forms a very + * specific scenario. + * + * @author guilherme.jansen@telestax.com + */ +public class RvdProjectsMigrationHelper { + + private static final String CONTEXT_NAME_RVD = "restcomm-rvd.war"; + private static final String WORKSPACE_DIRECTORY_NAME = "workspace"; + private static final String PROTO_DIRECTORY_PREFIX = "_proto"; + private static final String USERS_DIRECTORY_NAME = "@users"; + private static final Pattern RVD_PROJECT_URL = Pattern.compile("^\\/restcomm-rvd.*\\/(.*)\\/controller$"); + private static final String ACCOUNT_NOTIFICATIONS_SID = "ACae6e420f425248d6a26948c17a9e2acf"; + private static final String EMBEDDED_DIRECTORY_NAME = "workspace-migration"; + + private boolean embeddedMigration = false; // If restcomm-rvd context is not found, search for internal structure + + private Configuration configuration; + private String workspacePath; + private String workspaceBackupPath; + private StateHeader currentStateHeader; + private Application currentApplication; + private final ApplicationsDao applicationDao; + private final AccountsDao accountsDao; + private final IncomingPhoneNumbersDao didsDao; + private final ClientsDao clientsDao; + private final NotificationsDao notificationsDao; + private List dids; + private List clients; + private ActorRef emailService; + private ActorSystem system; + + public RvdProjectsMigrationHelper(ServletContext servletContext, Configuration configuration) throws Exception { + defineWorkspacePath(servletContext); + this.configuration = configuration; + final DaoManager storage = (DaoManager) servletContext.getAttribute(DaoManager.class.getName()); + this.applicationDao = storage.getApplicationsDao(); + this.accountsDao = storage.getAccountsDao(); + this.didsDao = storage.getIncomingPhoneNumbersDao(); + this.clientsDao = storage.getClientsDao(); + this.notificationsDao = storage.getNotificationsDao(); + system = (ActorSystem) servletContext.getAttribute(ActorSystem.class.getName()); + } + + private void defineWorkspacePath(ServletContext servletContext) throws Exception { + // Obtain RVD context root path + String contextRootPath = servletContext.getRealPath("/"); + String contextPathRvd = contextRootPath + "../" + CONTEXT_NAME_RVD + "/"; + + // Check RVD context to try embedded mode if necessary + File rvd = new File(contextPathRvd); + if (rvd.exists()) { + // Load RVD configuration and check workspace path + FileInputStream input = new FileInputStream(contextPathRvd + "WEB-INF/rvd.xml"); + XStream xstream = new XStream(); + xstream.alias("rvd", RvdConfig.class); + RvdConfig rvdConfig = (RvdConfig) xstream.fromXML(input); + // Define workspace location + String workspaceBasePath = contextPathRvd + WORKSPACE_DIRECTORY_NAME; + if (rvdConfig.getWorkspaceLocation() != null && !"".equals(rvdConfig.getWorkspaceLocation())) { + if (rvdConfig.getWorkspaceLocation().startsWith("/")) + workspaceBasePath = rvdConfig.getWorkspaceLocation(); // this is an absolute path + else + workspaceBasePath = contextPathRvd + rvdConfig.getWorkspaceLocation(); // this is a relative path hooked + // under RVD context + } + this.workspacePath = workspaceBasePath; + // Define workspace backup location + String workspaceBackupBasePath = contextPathRvd; + if (rvdConfig.getWorkspaceBackupLocation() != null && !"".equals(rvdConfig.getWorkspaceBackupLocation())) { + if (rvdConfig.getWorkspaceBackupLocation().startsWith("/")) + workspaceBackupBasePath = rvdConfig.getWorkspaceBackupLocation(); // this is an absolute path + else + workspaceBackupBasePath = contextPathRvd + rvdConfig.getWorkspaceBackupLocation(); // this is a relative + // path hooked under RVD + // context + } + this.workspaceBackupPath = workspaceBackupBasePath; + } else { + // Try to set embedded migration. For testing only + String dir = contextRootPath + EMBEDDED_DIRECTORY_NAME + File.separator + WORKSPACE_DIRECTORY_NAME + File.separator; + File embedded = new File(dir); + if (embedded.exists()) { + this.workspacePath = dir; + this.workspaceBackupPath = contextRootPath; + this.embeddedMigration = true; + } else { + throw new Exception("Error while searching for the workspace location. Aborting migration."); + } + } + + } + + public void backupWorkspace() throws RvdProjectsMigrationException { + try { + File workspace = new File(this.workspacePath); + File workspaceBackup = new File(this.workspaceBackupPath + File.separator + "workspaceBackup-" + + DateTime.now().getMillis()); + FileUtils.copyDirectoryToDirectory(workspace, workspaceBackup); + } catch (IOException e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:13] Error while creating backup for RVD workspace", 13); + } + } + + public List listProjects() throws RvdProjectsMigrationException { + List items = new ArrayList(); + File workspaceDir = new File(workspacePath); + if (workspaceDir.exists()) { + File[] entries = workspaceDir.listFiles(new FileFilter() { + @Override + public boolean accept(File anyfile) { + if (anyfile.isDirectory() && !anyfile.getName().startsWith(PROTO_DIRECTORY_PREFIX) + && !anyfile.getName().equals(USERS_DIRECTORY_NAME)) + return true; + return false; + } + }); + Arrays.sort(entries, new Comparator() { + @Override + public int compare(File f1, File f2) { + File statefile1 = new File(f1.getAbsolutePath() + File.separator + "state"); + File statefile2 = new File(f2.getAbsolutePath() + File.separator + "state"); + if (statefile1.exists() && statefile2.exists()) + return Long.valueOf(statefile2.lastModified()).compareTo(statefile1.lastModified()); + else + return Long.valueOf(f2.lastModified()).compareTo(f1.lastModified()); + } + }); + for (File entry : entries) { + items.add(entry.getName()); + } + } else { + throw new RvdProjectsMigrationException("[ERROR-CODE:1] Error while loading the list of projects from workspace", 1); + } + return items; + } + + public String searchApplicationSid(String projectName) throws RvdProjectsMigrationException { + try { + currentApplication = null; + String applicationSid = null; + currentApplication = applicationDao.getApplication(projectName); + if (currentApplication != null) { + applicationSid = currentApplication.getSid().toString(); + } else if (Sid.pattern.matcher(projectName).matches()) { + Sid sid = new Sid(projectName); + currentApplication = applicationDao.getApplication(sid); + if (currentApplication != null) { + applicationSid = currentApplication.getSid().toString(); + } + } + return applicationSid; + } catch ( TooManyResultsException e) { + /* This happens when a non-upgraded project whose friendly-name exists in several applications is upgraded. + The old bahaviour was a broken upgrade attempt for the whole workspace. + Now, the failure should be limited to this project + */ + throw new RvdProjectsMigrationException("[ERROR-CODE:14] Error while upgrading project '" + projectName + "'. Several applications with such a FriendlyName were found. You have to manually restore this project.", 14); + } + } + + public void renameProjectUsingNewConvention(String projectName, String applicationSid) throws RvdProjectsMigrationException { + try { + renameProject(projectName, applicationSid); + } catch (IOException e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:5] Error while renaming the project '" + projectName + + "' to '" + applicationSid + "'" + e.getMessage(), 5); + } + } + + public void renameProject(String source, String dest) throws IOException { + File sourceDir = new File(workspacePath + File.separator + source); + File destDir = new File(workspacePath + File.separator + dest); + FileUtils.moveDirectory(sourceDir, destDir); + } + + public void loadProjectState(String projectName) throws RvdProjectsMigrationException { + try { + String pathName = workspacePath + File.separator + projectName + File.separator + "state"; + File file = new File(pathName); + if (!file.exists()) { + throw new RvdProjectsMigrationException("File " + file.getPath() + "does not exist"); + } + String data = FileUtils.readFileToString(file, Charset.forName("UTF-8")); + JsonParser parser = new JsonParser(); + JsonElement headerElement = parser.parse(data).getAsJsonObject().get("header"); + if (headerElement == null) { + throw new RvdProjectsMigrationException(); + } + Gson gson = new Gson(); + currentStateHeader = gson.fromJson(headerElement, StateHeader.class); + } catch (IOException e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:6] Error loading state file from project '" + projectName + + "' " + e.getMessage(), 6); + } + } + + public boolean projectUsesNewNamingConvention(String projectName) { + return Sid.pattern.matcher(projectName).matches(); + } + + public String createOrUpdateApplicationEntity(String applicationSid, String projectName) + throws RvdProjectsMigrationException { + try { + if(applicationSid != null) { + // Update application + currentApplication = currentApplication.setRcmlUrl(URI.create("/restcomm-rvd/services/apps/" + applicationSid + + "/controller")); + applicationDao.updateApplication(currentApplication); + return applicationSid; + } else { + // Create new application + Account account = accountsDao.getAccount(currentStateHeader.getOwner()); + if (account == null) { + throw new RvdProjectsMigrationException("Error locating the owner account for project \"" + projectName + + "\""); + } + final Application.Builder builder = Application.builder(); + final Sid sid = Sid.generate(Sid.Type.APPLICATION); + builder.setSid(sid); + builder.setFriendlyName(projectName); + builder.setAccountSid(account.getSid()); + builder.setApiVersion(configuration.subset("runtime-settings").getString("api-version")); + builder.setHasVoiceCallerIdLookup(false); + String rootUri = configuration.subset("runtime-settings").getString("root-uri"); + rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); + final StringBuilder buffer = new StringBuilder(); + buffer.append(rootUri).append(configuration.subset("runtime-settings").getString("api-version")) + .append("/Accounts/").append(account.getSid().toString()).append("/Applications/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + builder.setRcmlUrl(URI.create("/restcomm-rvd/services/apps/" + sid.toString() + "/controller")); + builder.setKind(Application.Kind.getValueOf(currentStateHeader.getProjectKind())); + currentApplication = builder.build(); + applicationDao.addApplication(currentApplication); + return sid.toString(); + } + } catch (RvdProjectsMigrationException e) { + String suffix = currentApplication != null ? "with the application '" + currentApplication.getSid().toString() + + "' " : ""; + throw new RvdProjectsMigrationException("[ERROR-CODE:7] Error while synchronizing the project '" + projectName + + "' " + suffix + e.getMessage(), 7); + } + } + + public int updateIncomingPhoneNumbers(String applicationSid, String projectName) throws RvdProjectsMigrationException { + try { + + if (dids == null) { + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + dids = didsDao.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + } + } catch (Exception e) { + throw new RvdProjectsMigrationException( + "[ERROR-CODE:8] Error while loading IncomingPhoneNumbers list for updates with project '" + applicationSid + + "' " + e.getMessage(), 8); + } + Application.Kind kind = Application.Kind.getValueOf(currentStateHeader.getProjectKind()); + IncomingPhoneNumber did = null; + int amountUpdated = 0; + try { + switch (kind) { + case SMS: + for (int i = 0; i < dids.size(); i++) { + did = dids.get(i); + if (hasUrlReference(did.getSmsUrl(), currentApplication.getFriendlyName())) { + Sid smsApplicationSid = new Sid(applicationSid); + IncomingPhoneNumber updateSmsDid = new IncomingPhoneNumber(did.getSid(), did.getDateCreated(), + did.getDateUpdated(), did.getFriendlyName(), did.getAccountSid(), did.getPhoneNumber(), + did.getCost(), did.getApiVersion(), did.hasVoiceCallerIdLookup(), did.getVoiceUrl(), + did.getVoiceMethod(), did.getVoiceFallbackUrl(), did.getVoiceFallbackMethod(), + did.getStatusCallback(), did.getStatusCallbackMethod(), did.getVoiceApplicationSid(), null, + did.getSmsMethod(), did.getSmsFallbackUrl(), did.getSmsFallbackMethod(), smsApplicationSid, + did.getUri(), did.getUssdUrl(), did.getUssdMethod(), did.getUssdFallbackUrl(), + did.getUssdFallbackMethod(), did.getUssdApplicationSid(), + did.getReferUrl(), did.getReferMethod(), did.getReferApplicationSid(), + did.isVoiceCapable(), + did.isSmsCapable(), did.isMmsCapable(), did.isFaxCapable(), did.isPureSip(), did.getOrganizationSid()); + didsDao.updateIncomingPhoneNumber(updateSmsDid); + dids.set(i, updateSmsDid); + amountUpdated++; + } + } + break; + case USSD: + for (int i = 0; i < dids.size(); i++) { + did = dids.get(i); + if (hasUrlReference(did.getUssdUrl(), currentApplication.getFriendlyName())) { + Sid ussdApplicationSid = new Sid(applicationSid); + IncomingPhoneNumber updateUssdDid = new IncomingPhoneNumber(did.getSid(), did.getDateCreated(), + did.getDateUpdated(), did.getFriendlyName(), did.getAccountSid(), did.getPhoneNumber(), + did.getCost(), did.getApiVersion(), did.hasVoiceCallerIdLookup(), did.getVoiceUrl(), + did.getVoiceMethod(), did.getVoiceFallbackUrl(), did.getVoiceFallbackMethod(), + did.getStatusCallback(), did.getStatusCallbackMethod(), did.getVoiceApplicationSid(), + did.getSmsUrl(), did.getSmsMethod(), did.getSmsFallbackUrl(), did.getSmsFallbackMethod(), + did.getSmsApplicationSid(), did.getUri(), null, did.getUssdMethod(), + did.getUssdFallbackUrl(), did.getUssdFallbackMethod(), ussdApplicationSid, + did.getReferUrl(), did.getReferMethod(), did.getReferApplicationSid(), + did.isVoiceCapable(), did.isSmsCapable(), did.isMmsCapable(), did.isFaxCapable(), + did.isPureSip(), did.getOrganizationSid()); + didsDao.updateIncomingPhoneNumber(updateUssdDid); + dids.set(i, updateUssdDid); + amountUpdated++; + } + } + break; + case VOICE: + for (int i = 0; i < dids.size(); i++) { + did = dids.get(i); + if (hasUrlReference(did.getVoiceUrl(), currentApplication.getFriendlyName())) { + Sid voiceApplicationSid = new Sid(applicationSid); + IncomingPhoneNumber updateVoiceDid = new IncomingPhoneNumber(did.getSid(), did.getDateCreated(), + did.getDateUpdated(), did.getFriendlyName(), did.getAccountSid(), did.getPhoneNumber(), + did.getCost(), did.getApiVersion(), did.hasVoiceCallerIdLookup(), null, + did.getVoiceMethod(), did.getVoiceFallbackUrl(), did.getVoiceFallbackMethod(), + did.getStatusCallback(), did.getStatusCallbackMethod(), voiceApplicationSid, + did.getSmsUrl(), did.getSmsMethod(), did.getSmsFallbackUrl(), did.getSmsFallbackMethod(), + did.getSmsApplicationSid(), did.getUri(), did.getUssdUrl(), did.getUssdMethod(), + did.getUssdFallbackUrl(), did.getUssdFallbackMethod(), did.getUssdApplicationSid(), + did.getReferUrl(), did.getReferMethod(), did.getReferApplicationSid(), + did.isVoiceCapable(), did.isSmsCapable(), did.isMmsCapable(), did.isFaxCapable(), + did.isPureSip(), did.getOrganizationSid()); + didsDao.updateIncomingPhoneNumber(updateVoiceDid); + dids.set(i, updateVoiceDid); + amountUpdated++; + } + } + break; + default: + break; + } + } catch (UnsupportedEncodingException e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:9] Error while updating IncomingPhoneNumber '" + + did.getSid().toString() + "' with the Application '" + applicationSid + "' " + + e.getMessage(), 9); + } + return amountUpdated; + } + + private boolean hasUrlReference(URI url, String projectName) throws UnsupportedEncodingException { + if (url != null && !url.toString().isEmpty()) { + Matcher m = RVD_PROJECT_URL.matcher(url.toString()); + if (m.find()) { + String result = m.group(1); + result = URLDecoder.decode(result, "UTF-8"); + return projectName.equals(result); + } + } + return false; + } + + public int updateClients(String applicationSid, String projectName) throws RvdProjectsMigrationException { + try { + if (clients == null) { + clients = clientsDao.getAllClients(); + } + + } catch (Exception e) { + throw new RvdProjectsMigrationException( + "[ERROR-CODE:10] Error while loading the Clients list for updates with project '" + applicationSid + "'. " + + e.getMessage(), 10); + } + Application.Kind kind = Application.Kind.getValueOf(currentStateHeader.getProjectKind()); + Client client = null; + int amountUpdated = 0; + try { + if (kind == Application.Kind.VOICE) { + for (int i = 0; i < clients.size(); i++) { + client = clients.get(i); + if (hasUrlReference(client.getVoiceUrl(), currentApplication.getFriendlyName())) { + Sid voiceApplicationSid = new Sid(applicationSid); + client = client.setVoiceApplicationSid(voiceApplicationSid); + client = client.setVoiceUrl(null); + clientsDao.updateClient(client); + clients.set(i, client); + amountUpdated++; + } + } + } + } catch (Exception e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:11] Error while updating Client '" + + client.getSid().toString() + "' with the Application '" + applicationSid + "' " + + e.getMessage(), 11); + } + return amountUpdated; + } + + public void storeWorkspaceStatus(boolean migrationSucceeded) throws RvdProjectsMigrationException { + String pathName = workspacePath + File.separator + ".version"; + File file = new File(pathName); + Gson gson = new Gson(); + String version = org.restcomm.connect.commons.Version.getVersion(); + Version ws = new Version(migrationSucceeded, version); + String data = gson.toJson(ws); + try { + FileUtils.writeStringToFile(file, data, "UTF-8"); + } catch (IOException e) { + throw new RvdProjectsMigrationException("[ERROR-CODE:12] Error creating file in storage: " + file + e.getMessage(), + 12); + } + } + + public boolean isMigrationExecuted() { + String pathName = workspacePath + File.separator + ".version"; + File file = new File(pathName); + if (!file.exists()) { + return false; + } + String data; + try { + data = FileUtils.readFileToString(file, Charset.forName("UTF-8")); + } catch (IOException e) { + return false; + } + JsonParser parser = new JsonParser(); + JsonElement element = parser.parse(data).getAsJsonObject(); + if (element != null) { + Gson gson = new Gson(); + Version workspaceVersion = gson.fromJson(element, Version.class); + String restcommVersion = org.restcomm.connect.commons.Version.getVersion(); + if (!workspaceVersion.getVersion().equals(restcommVersion) && !workspaceVersion.getStatus()) { + return false; + } else { + return true; + } + } + return false; + } + + public void addNotification(String message, boolean error, Integer errorCode) throws URISyntaxException { + Notification.Builder builder = Notification.builder(); + Sid sid = Sid.generate(Sid.Type.NOTIFICATION); + builder.setSid(sid); + builder.setAccountSid(new Sid(ACCOUNT_NOTIFICATIONS_SID)); + builder.setApiVersion(configuration.subset("runtime-settings").getString("api-version")); + builder.setLog(error ? new Integer(1) : new Integer(0)); + builder.setErrorCode(errorCode); + builder.setMoreInfo(new URI("http://docs.telestax.com/rvd-workspace-upgrade")); + builder.setMessageText(message); + builder.setMessageDate(DateTime.now()); + builder.setRequestUrl(new URI("")); + builder.setRequestMethod(""); + builder.setRequestVariables(""); + StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(configuration.subset("runtime-settings").getString("api-version")).append("/Accounts/"); + buffer.append(ACCOUNT_NOTIFICATIONS_SID).append("/Notifications/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + + Notification notification = builder.build(); + notificationsDao.addNotification(notification); + } + + public boolean isMigrationEnabled() { + Boolean value = new Boolean(configuration.subset("runtime-settings").getString("rvd-workspace-migration-enabled", "true")); + return value; + } + + public void sendEmailNotification(String message, boolean migrationSucceeded) throws RvdProjectsMigrationException { + String host = configuration.subset("smtp-notify").getString("host"); + String username = configuration.subset("smtp-notify").getString("user"); + String password = configuration.subset("smtp-notify").getString("password"); + String defaultEmailAddress = configuration.subset("smtp-notify").getString("default-email-address"); + if (host == null || username == null || password == null || defaultEmailAddress == null || host.isEmpty() + || username.isEmpty() || password.isEmpty() || defaultEmailAddress.isEmpty()) { + throw new RvdProjectsMigrationException("Skipping email notification due to invalid configuration"); + } + if (emailService == null) { + emailService = emailService(configuration.subset("smtp-notify")); + } + + String subject = "Restcomm - RVD Projects migration"; + String body = message; + if (!migrationSucceeded) { + body += ". Please, visit http://docs.telestax.com/rvd-workspace-upgrade for more information on how to troubleshoot workspace migration issues."; + } + + final Mail emailMsg = new Mail(username + "@" + host, defaultEmailAddress, subject, body); + emailService.tell(new EmailRequest(emailMsg), emailService); + + } + + private ActorRef emailService(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public Actor create() throws Exception { + return new EmailService(configuration); + } + }); + return system.actorOf(props); + } + + public boolean isEmbeddedMigration() { + return this.embeddedMigration; + } + + private class Version { + + boolean status; + String version; + + public Version() { + + } + + public Version(boolean namingMigrationSucceeded, String versionLastRun) { + super(); + this.status = namingMigrationSucceeded; + this.version = versionLastRun; + } + + public boolean getStatus() { + return status; + } + + public String getVersion() { + return version; + } + + } + + private class RvdConfig { + private String workspaceLocation; + private String workspaceBackupLocation; + private String sslMode; + private String restcommBaseUrl; + + public RvdConfig() { + } + + public RvdConfig(String workspaceLocation, String workspaceBackupLocation, String restcommPublicIp, String sslMode) { + super(); + this.workspaceLocation = workspaceLocation; + this.workspaceBackupLocation = workspaceBackupLocation; + this.sslMode = sslMode; + } + + public String getWorkspaceLocation() { + return workspaceLocation; + } + + public String getWorkspaceBackupLocation() { + return workspaceBackupLocation; + } + + public String getSslMode() { + return sslMode; + } + + public String getRestcommBaseUrl() { + return restcommBaseUrl; + } + } + + private class StateHeader { + // application logging settings for this project. If not null logging is enabled. + // We are using an object instead of a boolean to easily add properties in the future + public class Logging { + } + + String projectKind; + String startNodeName; + String version; + String owner; // the Restcomm user id that owns the project or null if it has no owner at all. Added in 7.1.6 release + + // Logging logging; - moved to the separate 'settings' file + public StateHeader() { + } + + public StateHeader(String projectKind, String startNodeName, String version) { + super(); + this.projectKind = projectKind; + this.startNodeName = startNodeName; + this.version = version; + } + + public StateHeader(String projectKind, String startNodeName, String version, String owner) { + super(); + this.projectKind = projectKind; + this.startNodeName = startNodeName; + this.version = version; + this.owner = owner; + } + + public String getProjectKind() { + return projectKind; + } + + public String getStartNodeName() { + return startNodeName; + } + + public String getVersion() { + return version; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner2) { + this.owner = owner2; + } + + public void setVersion(String version) { + this.version = version; + } + } +} diff --git a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrator.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrator.java new file mode 100644 index 0000000000..3a4bea0774 --- /dev/null +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/RvdProjectsMigrator.java @@ -0,0 +1,287 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.application; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.joda.time.DateTimeZone; +import org.joda.time.LocalDateTime; + +import javax.servlet.ServletContext; +import java.io.File; +import java.io.FileWriter; +import java.net.URISyntaxException; +import java.sql.Timestamp; +import java.util.List; + +/** + * The goal of this class is to generate an Application entity inside the database for each RVD project located inside its + * workspace. Also, apply the new naming convention on project directories inside the workspace, based on a new + * {@link Sid.Type.PROJECT} generated to each entry. + * + * @author guilherme.jansen@telestax.com + */ +public class RvdProjectsMigrator { + + private static final Logger logger = Logger.getLogger(RvdProjectsMigrator.class); + private static final String separator = "--------------------------------------"; + private RvdProjectsMigrationHelper migrationHelper; + private List projectNames; + private boolean migrationSucceeded; + private Integer errorCode; + private String logPath; + + private int projectsProcessed; + private int projectsSuccess; + private int projectsError; + private int updatedDids; + private int updatedClients; + + public RvdProjectsMigrator(ServletContext servletContext, Configuration configuration) throws Exception { + this.migrationHelper = new RvdProjectsMigrationHelper(servletContext, configuration); + this.migrationSucceeded = true; + this.logPath = servletContext.getRealPath("/") + "../../../"; // Equivalent to RESTCOMM_HOME + this.errorCode = 0; + this.projectsProcessed = 0; + this.projectsSuccess = 0; + this.projectsError = 0; + this.updatedDids = 0; + this.updatedClients = 0; + } + + public void executeMigration() throws Exception { + String beginning = getTimeStamp(); + // Ensure the migration needs to be executed + if (!migrationHelper.isMigrationEnabled() || migrationHelper.isMigrationExecuted()) { + storeNewMessage("Workspace migration skipped in " + beginning, true, true, true, false); + storeNewMessage(separator, false, true, false, false); + return; + } + storeNewMessage("Starting workspace migration at " + beginning, true, true, true, false); + storeNewMessage(separator, false, true, false, false); + try { + if (!migrationHelper.isEmbeddedMigration()) { + backupWorkspace(); + } + loadProjectsList(); + } catch (RvdProjectsMigrationException e) { + migrationSucceeded = false; + errorCode = e.getErrorCode(); + storeNewMessage(e.getMessage(), true, true, false, true); + try { + storeMigrationStatus(); + } catch (Exception x) { + storeNewMessage("[ERROR-CODE:2] Error while storing workspace status" + x.getMessage(), true, true, false, true); + } + throw e; + } + for (String projectName : projectNames) { + try { + // Load Project State Header + migrationHelper.loadProjectState(projectName); + + // Check if this project is already synchronized with a application + String applicationSid = searchApplicationSid(projectName); + + // Synchronize with application entity if needed + applicationSid = synchronizeApplicationEntity(applicationSid, projectName); + + // Rename Project + migrateNamingConvention(projectName, applicationSid); + + // Update IncomingPhoneNumbers + updateIncomingPhoneNumbers(applicationSid, projectName); + + // Update Clients + updateClients(applicationSid, projectName); + + projectsSuccess++; + } catch (RvdProjectsMigrationException e) { + migrationSucceeded = false; + if (errorCode == 0) { // Keep the first error only + errorCode = e.getErrorCode(); + } + projectsError++; + storeNewMessage("Error while migrating project '" + projectName + "' " + e.getMessage(), false, true, false, + true); + } + projectsProcessed++; + storeNewMessage(separator, false, true, false, false); + } + try { + storeMigrationStatus(); + } catch (Exception e) { + storeNewMessage("[ERROR-CODE:2] Error while storing workspace status " + e, true, true, false, true); + throw e; + } + } + + private void loadProjectsList() throws Exception { + this.projectNames = migrationHelper.listProjects(); + } + + private String searchApplicationSid(String projectName) throws RvdProjectsMigrationException { + return migrationHelper.searchApplicationSid(projectName); + } + + private String synchronizeApplicationEntity(String applicationSid, String projectName) + throws RvdProjectsMigrationException, URISyntaxException { + if (!projectName.equals(applicationSid)) { + applicationSid = migrationHelper.createOrUpdateApplicationEntity(applicationSid, projectName); + storeNewMessage("Project '" + projectName + "' synchronized with Application '" + applicationSid + "'", false, + true, false, false); + } else { + storeNewMessage("Project '" + projectName + "' previously synchronized with Application '" + applicationSid + + "'. Skipped", false, true, false, false); + } + return applicationSid; + } + + private void migrateNamingConvention(String projectName, String applicationSid) throws RvdProjectsMigrationException, + URISyntaxException { + if (!projectName.equals(applicationSid)) { + migrationHelper.renameProjectUsingNewConvention(projectName, applicationSid); + storeNewMessage("Project '" + projectName + "' renamed to '" + applicationSid + "'", false, true, false, false); + } else { + storeNewMessage("Project " + projectName + " already using new naming convention. Skipped", false, true, false, + false); + } + } + + + private void updateIncomingPhoneNumbers(String applicationSid, String projectName) throws RvdProjectsMigrationException, + URISyntaxException { + int amountUpdated = migrationHelper.updateIncomingPhoneNumbers(applicationSid, projectName); + if (amountUpdated > 0) { + storeNewMessage("Updated " + amountUpdated + " IncomingPhoneNumbers with Application '" + applicationSid + "'", + false, true, false, false); + updatedDids += amountUpdated; + } else { + storeNewMessage("No IncomingPhoneNumbers found to update with Application '" + applicationSid + "'. Skipped", + false, true, false, false); + } + } + + private void updateClients(String applicationSid, String projectName) throws RvdProjectsMigrationException, URISyntaxException { + int amountUpdated = migrationHelper.updateClients(applicationSid, projectName); + if (amountUpdated > 0) { + storeNewMessage("Updated " + amountUpdated + " Clients with Application '" + applicationSid + "'", false, true, + false, false); + updatedClients += amountUpdated; + } else { + storeNewMessage("No Clients found to update with Application '" + applicationSid + "'. Skipped", false, true, + false, false); + } + } + + private void storeMigrationStatus() throws RvdProjectsMigrationException, URISyntaxException { + migrationHelper.storeWorkspaceStatus(migrationSucceeded); + String end = getTimeStamp(); + if (!migrationSucceeded) { + String message = "Workspace migration finished with errors at " + end; + message += ". Status: " + projectsProcessed + " Projects processed ("; + message += projectsSuccess + " with success and " + projectsError + " with error), "; + message += updatedDids + " IncomingPhoneNumbers and " + updatedClients + " Clients updated"; + storeNewMessage(message, true, true, true, true); + storeNewMessage(separator, false, true, false, false); + sendEmailNotification(message); + } else { + String message = "Workspace migration finished with success at " + end; + message += ". Status: " + projectsProcessed + " Projects processed ("; + message += projectsSuccess + " with success and " + projectsError + " with error), "; + message += updatedDids + " IncomingPhoneNumbers and " + updatedClients + " Clients updated"; + storeNewMessage(message, true, true, true, false); + storeNewMessage(separator, false, true, false, false); + sendEmailNotification(message); + } + } + + private void storeNewMessage(String message, boolean asServerLog, boolean asMigrationLog, boolean asNotification, + boolean error) throws RvdProjectsMigrationException, URISyntaxException { + // Write to server log + if (asServerLog) { + if (error) { + logger.error(message); + } else if(logger.isInfoEnabled()) { + logger.info(message); + } + } + // Write to migration log, but use server log if embedded migration + if (asMigrationLog) { + if (!migrationHelper.isEmbeddedMigration()) { + storeLogMessage(message); + } else if (!asServerLog) { // Prevent duplicated messages + if (error) { + logger.error(message); + } else if(logger.isInfoEnabled()) { + logger.info(message); + } + } + } + // Create new notification + if (asNotification) { + storeNewNotification(message); + } + } + + private void storeLogMessage(String message) throws RvdProjectsMigrationException, URISyntaxException { + try { + String pathName = logPath + "workspace-migration.log"; + File file = new File(pathName); + if (!file.exists()) { + file.createNewFile(); + } + FileWriter fw = new FileWriter(file, true); + fw.write(message + "\n"); + fw.close(); + } catch (Exception e) { + storeNewMessage("[ERROR-CODE:3] Error while writing to file RESTCOMM_HOME/workspace-migration.log", true, false, + false, true); + } + } + + private String getTimeStamp() { + LocalDateTime date = LocalDateTime.now(); + DateTimeZone tz = DateTimeZone.getDefault(); + return new Timestamp(date.toDateTime(tz).toDateTime(DateTimeZone.UTC).getMillis()).toString(); + } + + private void storeNewNotification(String message) throws URISyntaxException { + migrationHelper.addNotification(message, migrationSucceeded, new Integer(errorCode)); + } + + private void sendEmailNotification(String message) throws RvdProjectsMigrationException, URISyntaxException { + try { + migrationHelper.sendEmailNotification(message, migrationSucceeded); + } catch (RvdProjectsMigrationException e) { + storeNewMessage("[ERROR-CODE:4] Workspace migration email notification skipped due to invalid configuration", true, + true, false, + true); + storeNewMessage(separator, false, true, false, false); + } + } + + private void backupWorkspace() throws RvdProjectsMigrationException { + migrationHelper.backupWorkspace(); + } + +} diff --git a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/telephony/config/ConfigurationStringLookup.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/config/ConfigurationStringLookup.java similarity index 96% rename from restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/telephony/config/ConfigurationStringLookup.java rename to restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/config/ConfigurationStringLookup.java index 7ab36d23cb..c2f8c3e469 100644 --- a/restcomm/restcomm.application/src/main/java/org/mobicents/servlet/restcomm/telephony/config/ConfigurationStringLookup.java +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/config/ConfigurationStringLookup.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.telephony.config; +package org.restcomm.connect.application.config; import java.util.HashMap; import java.util.Map; diff --git a/restcomm/restcomm.application/src/main/resources/application.conf b/restcomm/restcomm.application/src/main/resources/application.conf index 13792bc2f2..443cbaa914 100644 --- a/restcomm/restcomm.application/src/main/resources/application.conf +++ b/restcomm/restcomm.application/src/main/resources/application.conf @@ -1,17 +1,41 @@ akka { - # Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT) -event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] - -# Log level used by the configured loggers (see "event-handlers") as soon -# as they have been started; before that, see "stdout-loglevel" -# Options: OFF, ERROR, WARNING, INFO, DEBUG -loglevel = "INFO" - -# Log level for the very basic logger activated during AkkaApplication startup -# Options: OFF, ERROR, WARNING, INFO, DEBUG -stdout-loglevel = "INFO" - -# Log the complete configuration at INFO level when the actor system is started. -# This is useful when you are uncertain of what configuration is used. -log-config-on-start = off + # Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT) + event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] + + # Log level used by the configured loggers (see "event-handlers") as soon + # as they have been started; before that, see "stdout-loglevel" + # Options: OFF, ERROR, WARNING, INFO, DEBUG + loglevel = "INFO" + + # Log level for the very basic logger activated during AkkaApplication startup + # Options: OFF, ERROR, WARNING, INFO, DEBUG + stdout-loglevel = "INFO" + + # Log the complete configuration at INFO level when the actor system is started. + # This is useful when you are uncertain of what configuration is used. + log-config-on-start = off + + # Configuration reference http://doc.akka.io/docs/akka/2.1.4/general/configuration.html + + actor { + + # The guardian "/user" will use this class to obtain its supervisorStrategy. + # It needs to be a subclass of akka.actor.SupervisorStrategyConfigurator. + # In addition to the default there is akka.actor.StoppingSupervisorStrategy. + guardian-supervisor-strategy = "org.restcomm.connect.commons.faulttolerance.RestcommSupervisorStrategy" + + # Timeout for ActorSystem.actorOf + # Default value 20s is too high + # creation-timeout = 20s + creation-timeout = 10s + } +} + +restcomm-blocking-dispatcher { + type = Dispatcher + executor = "thread-pool-executor" + thread-pool-executor { + fixed-pool-size = 32 + } + throughput = 1 } diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/dao-manager.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/dao-manager.xml new file mode 100644 index 0000000000..231bf6c52e --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/dao-manager.xml @@ -0,0 +1,24 @@ + + + + + + ${restcomm:home}/WEB-INF/conf/mybatis.xml + ${restcomm:home}/WEB-INF/data/hsql + ${restcomm:home}/WEB-INF/sql + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/defaultPlan.json b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/defaultPlan.json new file mode 100644 index 0000000000..0df876b35a --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/defaultPlan.json @@ -0,0 +1,16 @@ +{ + "featureEnablement": { + "DIDPurchase": {}, + "subaccountsCreation": {}, + "outboundPSTN": {}, + "inboundPSTN": {}, + "outboundSMS": {}, + "inboundSMS": {}, + "asr": {}, + "USSD": { + "provider": "default" + }, + "inboundUSSD": {}, + "outboundUSSD": {} + } +} \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml new file mode 100644 index 0000000000..3fb0ce7ea0 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/mybatis.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/mybatis.xml index 029ade3122..db052da8f7 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/mybatis.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/mybatis.xml @@ -4,8 +4,8 @@ @author thomas.quintana@telestax.com (Thomas Quintana) --> - - + + @@ -14,6 +14,16 @@ + + @@ -22,6 +32,7 @@ + @@ -35,5 +46,14 @@ + + + + + + + + + \ 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 40034670b6..9e0302f994 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 @@ -1,53 +1,272 @@ - 2012-04-24 + + false + - http://127.0.0.1:8080/restcomm/audio + /restcomm/audio + + + beep.wav + alert.wav + + + + 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 + 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 + + + + + 5 + + 60 + + + ${restcomm:home}/cache - http://127.0.0.1:8080/restcomm/cache + /restcomm/cache + + + false file://${restcomm:home}/recordings - http://127.0.0.1:8080/restcomm/recordings - + /restcomm/recordings + + + 2000 - http://127.0.0.1:8080/restcomm/errors - + /restcomm/errors - - true - + false + + + true + + + + false + + + 5060 + WebRTCGW__1@ + WebRTCGW/1.0 + + + + + + + + false + + true + + + + + + + + + + + + + + + + + + + + 60 + + - false - - true + + + true + + + false + + + + false + + + + false + + + false + + + + false + + false + + + + + @@ -57,23 +276,35 @@ - 127.0.0.1:5090 - + 127.0.0.1:5090 + + + + + false + + + true false - 20 true + false restcomm restcomm restcomm_instance_id + site_id http://127.0.0.1:2080 @@ -84,7 +315,57 @@ - + + http://GMLC-IP:port/restcomm/gmlc/rest?msisdn= + + + + + + + + + + + + + + + 3600 + + + + boolean + string + + + + @@ -105,115 +386,338 @@ RestComm:Read:SmsMessages RestComm:Read:Transcriptions RestComm:*:OutboundProxies + RestComm:*:EmailMessages + RestComm:*:Usage + RestComm:*:Geolocation + + 14400 - - + + + + + + + - - - - - - - - + + + + https://backoffice.voipinnovations.com/api2.pl - + + + + + + + https://api.inetwork.com/v1.0 + + + + + https://rest.nexmo.com/ + + + + + + https://api.voxbone.com/ws-voxbone/services/rest + - + + + + + + + + + + - - - - ${restcomm:home}/WEB-INF/conf/mybatis.xml - - ${restcomm:home}/WEB-INF/data/hsql - ${restcomm:home}/WEB-INF/sql - - - + + + + + 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 - - + + 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 @@ -244,17 +748,49 @@ 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 + + + + + - \ No newline at end of file + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/shiro.ini b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/shiro.ini index 7412a394c1..0499fccd2a 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/shiro.ini +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/shiro.ini @@ -1,6 +1,6 @@ [main] -authcBasicRealm = org.mobicents.servlet.restcomm.entities.shiro.Realm -matcher = org.mobicents.servlet.restcomm.entities.shiro.CredentialsMatcher +authcBasicRealm = org.restcomm.connect.dao.entities.shiro.Realm +matcher = org.restcomm.connect.dao.entities.shiro.CredentialsMatcher authcBasicRealm.credentialsMatcher = $matcher [urls] diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.properties b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.properties index 40f0b27d2c..03e5480d57 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.properties +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.properties @@ -1,5 +1,5 @@ -#HSQL Database Engine 1.8.0.8 -#Thu Apr 26 22:35:53 EDT 2012 +#HSQL Database Engine 2.3.2 +#Mon Oct 13 15:44:12 CST 2014 hsqldb.script_format=0 runtime.gc_interval=0 sql.enforce_strict_size=false @@ -7,7 +7,7 @@ hsqldb.cache_size_scale=8 readonly=false hsqldb.nio_data_file=true hsqldb.cache_scale=14 -version=1.8.0 +version=2.3.2 hsqldb.default_table_type=memory hsqldb.cache_file_scale=1 hsqldb.log_size=200 diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script index c4ac15ae12..258875e554 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script @@ -1,35 +1,55 @@ CREATE SCHEMA PUBLIC AUTHORIZATION DBA -CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_instance_id"("instance_id" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL, "host" VARCHAR(255) NOT NULL) +CREATE MEMORY TABLE "restcomm_organizations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "domain_name" VARCHAR(255) NOT NULL UNIQUE, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "status" VARCHAR(16)) +CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL, "organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') CREATE MEMORY TABLE "restcomm_announcements"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"account_sid" VARCHAR(34),"gender" VARCHAR(8) NOT NULL,"language" VARCHAR(16) NOT NULL,"text" VARCHAR(32) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL, "voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN) +CREATE MEMORY TABLE "restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL,"voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN,"cost" VARCHAR(10)) CREATE MEMORY TABLE "restcomm_outgoing_caller_ids"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"uri" LONGVARCHAR NOT NULL) CREATE MEMORY TABLE "restcomm_http_cookies"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"comment" LONGVARCHAR,"domain" LONGVARCHAR,"expiration_date" DATETIME,"name" LONGVARCHAR NOT NULL,"path" LONGVARCHAR,"value" LONGVARCHAR,"version" INT) -CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN) -CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_caller_id_lookup" BOOLEAN NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_status_callback" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(34),"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(11) NOT NULL,"start_time" DATETIME,"end_time" DATETIME,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(13) NOT NULL,"answered_by" VARCHAR(7),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(15),"caller_name" VARCHAR(30),"uri" LONGVARCHAR NOT NULL, "call_path" VARCHAR(255)) -CREATE MEMORY TABLE "restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_expires" DATETIME NOT NULL,"address_of_record" LONGVARCHAR NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" LONGVARCHAR,"ttl" INTEGER NOT NULL,"location" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(30) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN, "pure_sip" BOOLEAN,"cost" VARCHAR(10), "ussd_url" LONGVARCHAR, "ussd_method" VARCHAR(4), "ussd_fallback_url" LONGVARCHAR, "ussd_fallback_method" VARCHAR(4), "ussd_application_sid" VARCHAR(34), "refer_url" LONGVARCHAR, "refer_method" VARCHAR(4), "refer_application_sid" VARCHAR(34), "organization_sid" VARCHAR(34) NOT NULL) +CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"uri" LONGVARCHAR NOT NULL,"rcml_url" LONGVARCHAR, "kind" VARCHAR(5)) +CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(1000) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(1000),"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(255) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(20) NOT NULL,"start_time" DATETIME,"end_time" DATETIME,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(20) NOT NULL,"answered_by" VARCHAR(64),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(30),"caller_name" VARCHAR(50),"uri" LONGVARCHAR NOT NULL, "call_path" VARCHAR(255),"ring_duration" INTEGER, "instanceid" VARCHAR(255) NOT NULL, "conference_sid" VARCHAR(34),"muted" BOOLEAN, "start_conference_on_enter" BOOLEAN, "end_conference_on_exit" BOOLEAN, "on_hold" BOOLEAN, "ms_id" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_conference_detail_records" ( "sid" VARCHAR(34) NOT NULL PRIMARY KEY, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "account_sid" VARCHAR(34) NOT NULL, "status" VARCHAR(100) NOT NULL, "friendly_name" VARCHAR(60), "api_version" VARCHAR(10) NOT NULL, "uri" LONGVARCHAR NOT NULL, "master_ms_id" VARCHAR(34),"master_conference_endpoint_id" VARCHAR(20),"master_present" BOOLEAN DEFAULT TRUE, "master_ivr_endpoint_id" VARCHAR(20),"master_ivr_endpoint_session_id" VARCHAR(200),"master_bridge_endpoint_id" VARCHAR(20),"master_bridge_endpoint_session_id" VARCHAR(200),"master_bridge_conn_id" VARCHAR(200),"master_ivr_conn_id" VARCHAR(200)) +CREATE MEMORY TABLE "restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "push_client_identity" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_expires" DATETIME NOT NULL,"address_of_record" LONGVARCHAR NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" LONGVARCHAR,"ttl" INTEGER NOT NULL,"location" LONGVARCHAR NOT NULL, "webrtc" BOOLEAN DEFAULT FALSE, "instanceid" VARCHAR(255), "isLBPresent" BOOLEAN DEFAULT FALSE, "organization_sid" VARCHAR(34)) CREATE MEMORY TABLE "restcomm_short_codes"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"short_code" INTEGER NOT NULL,"api_version" VARCHAR(10) NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_sent" DATETIME,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"body" VARCHAR(160) NOT NULL,"status" VARCHAR(7) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_sent" DATETIME,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(255) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"body" VARCHAR(999) NOT NULL,"status" VARCHAR(20) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL, "file_uri" LONGVARCHAR, "s3_uri" LONGVARCHAR) CREATE MEMORY TABLE "restcomm_transcriptions"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(11) NOT NULL,"recording_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"transcription_text" LONGVARCHAR,"price" VARCHAR(8) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" LONGVARCHAR NOT NULL,"message_text" LONGVARCHAR NOT NULL,"message_date" DATETIME NOT NULL,"request_url" LONGVARCHAR NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" LONGVARCHAR NOT NULL,"response_headers" LONGVARCHAR,"response_body" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" LONGVARCHAR NOT NULL,"message_text" LONGVARCHAR NOT NULL,"message_date" DATETIME NOT NULL,"request_url" LONGVARCHAR NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" LONGVARCHAR NOT NULL,"response_headers" LONGVARCHAR,"response_body" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) CREATE MEMORY TABLE "restcomm_sand_boxes"("date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"pin" VARCHAR(8) NOT NULL,"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY,"phone_number" VARCHAR(15) NOT NULL,"application_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) CREATE MEMORY TABLE "restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(255),"user_name" VARCHAR(255),"password" VARCHAR(255),"proxy" LONGVARCHAR NOT NULL,"register" BOOLEAN NOT NULL,"ttl" INT NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_media_servers" ( "ms_id" INT GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, "local_ip" VARCHAR(34) NOT NULL, "local_port" INT NOT NULL, "remote_ip" VARCHAR(34) NOT NULL UNIQUE, "remote_port" INT NOT NULL, "compatibility" VARCHAR(34) DEFAULT 'rms', "response_timeout" VARCHAR(34), "external_address" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_media_resource_broker_entity" ("conference_sid" VARCHAR(34) NOT NULL, "slave_ms_id" VARCHAR(34) NOT NULL, "slave_ms_bridge_ep_id" VARCHAR(34),"slave_ms_cnf_ep_id" VARCHAR(34),"is_bridged_together" BOOLEAN DEFAULT FALSE,PRIMARY KEY ("conference_sid" , "slave_ms_id")) +CREATE MEMORY TABLE PUBLIC."restcomm_extensions_configuration"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"extension" VARCHAR(255) NOT NULL,"configuration_data" VARCHAR(16777216),"configuration_type" VARCHAR(255) NOT NULL,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP, "enabled" BOOLEAN DEFAULT TRUE NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_accounts_extensions" ("account_sid" VARCHAR(34) NOT NULL, "extension_sid" VARCHAR(34) NOT NULL, PRIMARY KEY("account_sid", "extension_sid"), "configuration_data" VARCHAR(16777216)) +CREATE MEMORY TABLE "restcomm_geolocation"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "date_executed" DATETIME NOT NULL, "account_sid" VARCHAR(34) NOT NULL, "source" VARCHAR(30), "device_identifier" VARCHAR(30) NOT NULL, "geolocation_type" VARCHAR(15) NOT NULL, "response_status" VARCHAR(30), "cell_id" VARCHAR(10), "location_area_code" VARCHAR(10), "mobile_country_code" INTEGER, "mobile_network_code" VARCHAR(3), "network_entity_address" BIGINT, "age_of_location_info" INTEGER, "device_latitude" VARCHAR(15), "device_longitude" VARCHAR(15), "accuracy" BIGINT, "physical_address" VARCHAR(50), "internet_address" VARCHAR(50), "formatted_address" VARCHAR(200), "location_timestamp" DATETIME, "event_geofence_latitude" VARCHAR(15), "event_geofence_longitude" VARCHAR(15), "radius" BIGINT, "geolocation_positioning_type" VARCHAR(15), "last_geolocation_response" VARCHAR(10), "cause" VARCHAR(150), "api_version" VARCHAR(10) NOT NULL, "uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_profile_associations"("target_sid" VARCHAR(34) NOT NULL PRIMARY KEY, "profile_sid" VARCHAR(34) NOT NULL, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL) +CREATE MEMORY TABLE "restcomm_profiles"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "document" LONGVARCHAR NOT NULL, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL) +CREATE PROCEDURE PUBLIC."completeConferenceDetailRecord"(IN "in_sid" VARCHAR(100),IN "in_status" VARCHAR(100),IN "in_slave_ms_id" VARCHAR(100),IN "in_date_updated" TIMESTAMP,IN "amIMaster" BOOLEAN,OUT "completed" BOOLEAN) SPECIFIC "completeConferenceDetailRecord_10482" LANGUAGE SQL NOT DETERMINISTIC MODIFIES SQL DATA NEW SAVEPOINT LEVEL BEGIN ATOMIC SET "completed"=FALSE;IF("amIMaster")THEN UPDATE PUBLIC."restcomm_conference_detail_records" SET PUBLIC."restcomm_conference_detail_records"."master_present"=FALSE,PUBLIC."restcomm_conference_detail_records"."date_updated"="in_date_updated" WHERE PUBLIC."restcomm_conference_detail_records"."sid"="in_sid";IF NOT EXISTS(SELECT PUBLIC."restcomm_media_resource_broker_entity"."conference_sid",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_id",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_bridge_ep_id",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_cnf_ep_id",PUBLIC."restcomm_media_resource_broker_entity"."is_bridged_together" FROM PUBLIC."restcomm_media_resource_broker_entity" WHERE "conference_sid"="in_sid")THEN UPDATE PUBLIC."restcomm_conference_detail_records" SET "status"="in_status","date_updated"="in_date_updated" WHERE "sid"="in_sid";SET "completed"=TRUE;END IF;ELSE DELETE FROM PUBLIC."restcomm_media_resource_broker_entity" WHERE "conference_sid"="in_sid" AND "slave_ms_id"="in_slave_ms_id";IF NOT(SELECT "master_present" FROM PUBLIC."restcomm_conference_detail_records" WHERE "sid"="in_sid")THEN IF NOT EXISTS(SELECT PUBLIC."restcomm_media_resource_broker_entity"."conference_sid",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_id",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_bridge_ep_id",PUBLIC."restcomm_media_resource_broker_entity"."slave_ms_cnf_ep_id",PUBLIC."restcomm_media_resource_broker_entity"."is_bridged_together" FROM PUBLIC."restcomm_media_resource_broker_entity" WHERE "conference_sid"="in_sid")THEN UPDATE PUBLIC."restcomm_conference_detail_records" SET "status"="in_status","date_updated"="in_date_updated" WHERE "sid"="in_sid";SET "completed"=TRUE;END IF;END IF;END IF;END CREATE USER SA PASSWORD "" GRANT DBA TO SA SET WRITE_DELAY 10 SET SCHEMA PUBLIC -INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','2012-04-24','administrator@company.com','Default Administrator Account',NULL,'Full','uninitialized','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN146638eec1e2415d832785e30d227598','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','235','ACae6e420f425248d6a26948c17a9e2acf','+1235','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNabf9c98b95d64b26b5993ad52e809566','2013-10-11 14:55:56.670000000','2013-10-11 14:55:56.670000000','236','ACae6e420f425248d6a26948c17a9e2acf','+1236','2012-04-24',FALSE,'/restcomm/demos/gather/hello-gather.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNabf9c98b95d64b26b5993ad52e809566') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNdd7a0a0248244615978bd5781598e5eb','2013-10-04 17:42:02.500000000','2013-10-04 17:42:02.500000000','234','ACae6e420f425248d6a26948c17a9e2acf','+1234','2012-04-24',FALSE,'/restcomm/demos/hello-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN91275300c95547039c3723a1e58b5662','2013-10-31 22:12:19.318000000','2013-10-31 22:12:19.318000000','237','ACae6e420f425248d6a26948c17a9e2acf','+1237','2012-04-24',FALSE,'/restcomm/demos/dial/sip/dial-sip.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN91275300c95547039c3723a1e58b5662') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN0b4201c6c87749f29367e6cf000686cb','2013-11-04 12:14:10.520000000','2013-11-04 12:14:10.520000000','238','ACae6e420f425248d6a26948c17a9e2acf','+1238','2012-04-24',FALSE,'/restcomm/demos/dial/client/dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN0b4201c6c87749f29367e6cf000686cb') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN9f27f81e725640d988486ff15f48ad18','2013-11-04 12:42:11.530000000','2013-11-04 12:42:11.530000000','310','ACae6e420f425248d6a26948c17a9e2acf','+1310','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9f27f81e725640d988486ff15f48ad18') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN3862668c51634d18ae027c63438b4583','2013-11-04 12:42:44.777000000','2013-11-04 12:42:44.777000000','311','ACae6e420f425248d6a26948c17a9e2acf','+1311','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN3862668c51634d18ae027c63438b4583') -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNc2b81d68a221482ea387b6b4e2cbd9d7','2014-02-17 22:36:58.008000000','2014-02-17 22:36:58.008000000','239','ACae6e420f425248d6a26948c17a9e2acf','+1239','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdSayVerbDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNc2b81d68a221482ea387b6b4e2cbd9d7',NULL,NULL,NULL,NULL) -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000000','2014-02-17 22:37:08.709000000','240','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdCollectVerbDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',NULL,NULL,NULL,NULL) -INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNb43ed9e641364277b6432547ff1109e9','2014-02-17 22:37:19.392000000','2014-02-17 22:37:19.392000000','241','ACae6e420f425248d6a26948c17a9e2acf','+1241','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdESDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNb43ed9e641364277b6432547ff1109e9',NULL,NULL,NULL,NULL) -INSERT INTO "restcomm_clients" VALUES('CLa2b99142e111427fbb489c3de357f60a','2013-11-04 12:52:44.144000000','2013-11-04 12:52:44.144000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','alice','alice','1234',1,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a') -INSERT INTO "restcomm_clients" VALUES('CL3003328d0de04ba68f38de85b732ed56','2013-11-04 16:33:39.248000000','2013-11-04 16:33:39.248000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','bob','bob','1234',1,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56') +INSERT INTO "restcomm_organizations" VALUES('ORafbe225ad37541eba518a74248f0ac4c', 'default.restcomm.com', '2017-04-19 00:00:00.000000000','2017-04-19 00:00:00.000000000', 'active') +INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','administrator@company.com','Default Administrator Account',NULL,'Full','uninitialized','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_applications" VALUES('AP73926e7113fa4d95981aa96b76eca854','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','rvdCollectVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP81cf45088cba4abcac1261385916d582','2015-09-23 06:56:17.977000','2015-09-23 06:56:17.977000','rvdESDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP81cf45088cba4abcac1261385916d582','/restcomm-rvd/services/apps/AP81cf45088cba4abcac1261385916d582/controller','voice') +INSERT INTO "restcomm_applications" VALUES('APb70c33bf0b6748f09eaec97030af36f3','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','rvdSayVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APb70c33bf0b6748f09eaec97030af36f3','/restcomm-rvd/services/apps/APb70c33bf0b6748f09eaec97030af36f3/controller','voice') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN146638eec1e2415d832785e30d227598','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','This app plays the Hello World msg and requires Text-to-speech ','ACae6e420f425248d6a26948c17a9e2acf','+1235','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNabf9c98b95d64b26b5993ad52e809566','2013-10-11 14:55:56.670000000','2013-10-11 14:55:56.670000000','This app uses the collect verb to get user input','ACae6e420f425248d6a26948c17a9e2acf','+1236','2012-04-24',FALSE,'/restcomm/demos/gather/hello-gather.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNabf9c98b95d64b26b5993ad52e809566',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNdd7a0a0248244615978bd5781598e5eb','2013-10-04 17:42:02.500000000','2013-10-04 17:42:02.500000000','This app plays pre-recorded audio file','ACae6e420f425248d6a26948c17a9e2acf','+1234','2012-04-24',FALSE,'/restcomm/demos/hello-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN91275300c95547039c3723a1e58b5662','2013-10-31 22:12:19.318000000','2013-10-31 22:12:19.318000000','This app requires that you configure the sip:username@ipaddress:port','ACae6e420f425248d6a26948c17a9e2acf','+1237','2012-04-24',FALSE,'/restcomm/demos/dial/sip/dial-sip.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN91275300c95547039c3723a1e58b5662',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN0b4201c6c87749f29367e6cf000686cb','2013-11-04 12:14:10.520000000','2013-11-04 12:14:10.520000000','This app calls registered restcomm client Alice ','ACae6e420f425248d6a26948c17a9e2acf','+1238','2012-04-24',FALSE,'/restcomm/demos/dial/client/dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN0b4201c6c87749f29367e6cf000686cb',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN9f27f81e725640d988486ff15f48ad18','2013-11-04 12:42:11.530000000','2013-11-04 12:42:11.530000000','This app join a conf bridge with wait music playing ','ACae6e420f425248d6a26948c17a9e2acf','+1310','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9f27f81e725640d988486ff15f48ad18',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN3862668c51634d18ae027c63438b4583','2013-11-04 12:42:44.777000000','2013-11-04 12:42:44.777000000','This app adds you to a conf bridge as a moderator','ACae6e420f425248d6a26948c17a9e2acf','+1311','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN3862668c51634d18ae027c63438b4583',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNc2b81d68a221482ea387b6b4e2cbd9d7','2014-02-17 22:36:58.008000000','2014-02-17 22:36:58.008000000','This makes a call to a basic RVD app ','ACae6e420f425248d6a26948c17a9e2acf','+1239','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','APb70c33bf0b6748f09eaec97030af36f3',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNc2b81d68a221482ea387b6b4e2cbd9d7',NULL,NULL,NULL,NULL,TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000000','2014-02-17 22:37:08.709000000','This is an IVR app that maps user input to specific action','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP73926e7113fa4d95981aa96b76eca854',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',NULL,NULL,NULL,NULL,TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNb43ed9e641364277b6432547ff1109e9','2014-02-17 22:37:19.392000000','2014-02-17 22:37:19.392000000','RVD external services app, customer ID 1 or 2 ','ACae6e420f425248d6a26948c17a9e2acf','+1241','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP81cf45088cba4abcac1261385916d582',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNb43ed9e641364277b6432547ff1109e9',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN78341988ed59478d89a37bd820d94fb8','2017-02-08 11:11:23.948000000','2017-02-08 11:11:23.948000000','This app plays the video demonstration and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1242','2012-04-24',FALSE,'/restcomm/demos/video-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN78341988ed59478d89a37bd820d94fb8',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN9154cd100e894cccb9846542b831f8f0','2017-03-08 04:29:30.827000000','2017-03-08 04:29:30.827000000','This app records a video message and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1243','2012-04-24',FALSE,'/restcomm/demos/video-record.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9154cd100e894cccb9846542b831f8f0',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN268b3f55d3a84a70aae8b78bde3443b5','2017-04-13 22:03:27.925000000','2017-04-13 22:03:27.925000000','This app joins a video conf bridge with wait music playing and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1244','2012-04-24',FALSE,'/restcomm/demos/video-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN268b3f55d3a84a70aae8b78bde3443b5',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNa956a87b060b4b93bf432fce19fe79bf','2017-04-13 22:04:04.258000000','2017-04-13 22:04:04.258000000','This app adds you to a video conf bridge as a moderator and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1245','2012-04-24',FALSE,'/restcomm/demos/video-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNa956a87b060b4b93bf432fce19fe79bf',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN5eadc8c3b26a495a842bbff6aecc9f6c','2017-09-29 19:34:10.679000000','2017-09-29 19:34:10.679000000','This app calls registered restcomm client Alice using XMS for video','ACae6e420f425248d6a26948c17a9e2acf','+1246','2012-04-24',FALSE,'/restcomm/demos/video-dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN5eadc8c3b26a495a842bbff6aecc9f6c',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_clients" VALUES('CLa2b99142e111427fbb489c3de357f60a','2013-11-04 12:52:44.144000000','2013-11-04 12:52:44.144000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','alice','alice','1234',1,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a',NULL) +INSERT INTO "restcomm_clients" VALUES('CL3003328d0de04ba68f38de85b732ed56','2013-11-04 16:33:39.248000000','2013-11-04 16:33:39.248000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','bob','bob','1234',1,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56',NULL) diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/README b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/README new file mode 100644 index 0000000000..9f1aa44295 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/README @@ -0,0 +1 @@ +Changelog scripts are depreciated. Use upgrade script at $RESTCOMM_HOME/bin/restcomm/upgrade.sh, see http://documentation.telestax.com/connect/configuration/How%20to%20use%20Mysql%20schema%20upgrade%20scripts.html#mysql-schema-upgrade diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Apr29_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Apr29_2016.sql new file mode 100644 index 0000000000..6dd8ed52d3 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Apr29_2016.sql @@ -0,0 +1,12 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #1026 +#Date: Apr 29 +#Author: Guilherme Humberto Jansen + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +UPDATE restcomm_incoming_phone_numbers SET voice_method = 'POST' WHERE voice_method IS NULL AND voice_application_sid IS NOT NULL; +UPDATE restcomm_incoming_phone_numbers SET sms_method = 'POST' WHERE sms_method IS NULL AND sms_application_sid IS NOT NULL; +UPDATE restcomm_incoming_phone_numbers SET ussd_method = 'POST' WHERE ussd_method IS NULL AND ussd_application_sid IS NOT NULL; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_April26_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_April26_2016.sql new file mode 100644 index 0000000000..5a8349519d --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_April26_2016.sql @@ -0,0 +1,11 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #1009 +#Date: Mar 11, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#Modify table "restcomm_registrations", add 'instanceid' VARCHAR(255) +ALTER TABLE restcomm_registrations ADD instanceid VARCHAR(255); + +INSERT INTO update_scripts VALUES ('update_script_April26_2016 for issue #1009', NOW()); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Dec14_2015.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Dec14_2015.sql new file mode 100644 index 0000000000..bb72a94295 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Dec14_2015.sql @@ -0,0 +1,20 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #530 +#Date: Dec 14 +#Author: Guilherme Humberto Jansen + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +USE restcomm; + +-- backup applications +CREATE TABLE restcomm_applications_migrationbkp LIKE restcomm_applications; +INSERT restcomm_applications_migrationbkp SELECT * FROM restcomm_applications; + +-- backup incoming phone numbers +CREATE TABLE restcomm_incoming_phone_numbers_migrationbkp LIKE restcomm_incoming_phone_numbers; +INSERT restcomm_incoming_phone_numbers_migrationbkp SELECT * FROM restcomm_incoming_phone_numbers; + +-- backup clients +CREATE TABLE restcomm_clients_migrationbkp LIKE restcomm_clients; +INSERT restcomm_clients_migrationbkp SELECT * FROM restcomm_clients; diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb20_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb20_2016.sql new file mode 100644 index 0000000000..a05ff2430b --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb20_2016.sql @@ -0,0 +1,13 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #885 +#Date: Feb 20, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +CREATE TABLE update_scripts ( +script VARCHAR(255) NOT NULL, +date_executed DATETIME NOT NULL +); + +INSERT INTO update_scripts VALUES ('update_script_Feb20_2016', NOW()); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb22_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb22_2016.sql new file mode 100644 index 0000000000..e3c1f89a09 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb22_2016.sql @@ -0,0 +1,15 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #829 +#Date: Jan 2 +#Author: Guilherme Humberto Jansen + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +UPDATE restcomm_incoming_phone_numbers SET voice_url = NULL, voice_application_sid = 'APb70c33bf0b6748f09eaec97030af36f3' WHERE sid = 'PNc2b81d68a221482ea387b6b4e2cbd9d7'; +UPDATE restcomm_incoming_phone_numbers SET voice_url = NULL, voice_application_sid = 'AP73926e7113fa4d95981aa96b76eca854' WHERE sid = 'PN46678e5b01d44973bf184f6527bc33f7'; +UPDATE restcomm_incoming_phone_numbers SET voice_url = NULL, voice_application_sid = 'AP81cf45088cba4abcac1261385916d582' WHERE sid = 'PNb43ed9e641364277b6432547ff1109e9'; +UPDATE restcomm_applications SET rcml_url = '/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller' WHERE sid = 'AP73926e7113fa4d95981aa96b76eca854'; +UPDATE restcomm_applications SET rcml_url = '/restcomm-rvd/services/apps/AP81cf45088cba4abcac1261385916d582/controller' WHERE sid = 'AP81cf45088cba4abcac1261385916d582'; +UPDATE restcomm_applications SET rcml_url = '/restcomm-rvd/services/apps/APb70c33bf0b6748f09eaec97030af36f3/controller' WHERE sid = 'APb70c33bf0b6748f09eaec97030af36f3'; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb26_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb26_2016.sql new file mode 100644 index 0000000000..d07c9c8461 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb26_2016.sql @@ -0,0 +1,11 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #900 +#Date: Feb 26, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#Modify table "restcomm_sms_messages", change 'body' length to 999 +ALTER TABLE restcomm_sms_messages MODIFY body VARCHAR(999); + +INSERT INTO update_scripts VALUES ('update_script_Feb26_2016', NOW()); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb2_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb2_2016.sql new file mode 100644 index 0000000000..1ff4c18f8e --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Feb2_2016.sql @@ -0,0 +1,12 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #829 +#Date: Jan 2 +#Author: Guilherme Humberto Jansen + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +UPDATE restcomm_incoming_phone_numbers SET voice_url = '/restcomm-rvd/services/apps/rvdSayVerbDemo/controller', voice_application_sid = NULL WHERE sid = 'PNc2b81d68a221482ea387b6b4e2cbd9d7'; +UPDATE restcomm_incoming_phone_numbers SET voice_url = '/restcomm-rvd/services/apps/rvdCollectVerbDemo/controller', voice_application_sid = NULL WHERE sid = 'PN46678e5b01d44973bf184f6527bc33f7'; +UPDATE restcomm_incoming_phone_numbers SET voice_url = '/restcomm-rvd/services/apps/rvdESDemo/controller', voice_application_sid = NULL WHERE sid = 'PNb43ed9e641364277b6432547ff1109e9'; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Jan21_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Jan21_2016.sql new file mode 100644 index 0000000000..7db808252f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Jan21_2016.sql @@ -0,0 +1,76 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #798 +#Date: Jan 21, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +USE restcomm; + +#Modify table "restcomm_incoming_phone_numbers", add columns for ussd url, fallback and ussd application sid to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table ADD ussd_url MEDIUMTEXT; +ALTER TABLE temp_table ADD ussd_method VARCHAR(4); +ALTER TABLE temp_table ADD ussd_fallback_url MEDIUMTEXT; +ALTER TABLE temp_table ADD ussd_fallback_method VARCHAR(4); +ALTER TABLE temp_table ADD ussd_application_sid VARCHAR(34); +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + friendly_name, + account_sid, + phone_number, + api_version, + voice_caller_id_lookup, + voice_url, + voice_method, + voice_fallback_url, + voice_fallback_method, + status_callback, + status_callback_method, + voice_application_sid, + sms_url, + sms_method, + sms_fallback_url, + sms_fallback_method, + sms_application_sid, + uri, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + pure_sip, + cost +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + friendly_name as friendly_name, + account_sid as account_sid, + phone_number as phone_number, + api_version as api_version, + voice_caller_id_lookup as voice_caller_id_lookup, + voice_url as voice_url, + voice_method as voice_method, + voice_fallback_url as voice_fallback_url, + voice_fallback_method as voice_fallback_method, + status_callback as status_callback, + status_callback_method as status_callback_method, + voice_application_sid as voice_application_sid, + sms_url as sms_url, + sms_method as sms_method, + sms_fallback_url as sms_fallback_url, + sms_fallback_method as sms_fallback_method, + sms_application_sid as sms_application_sid, + uri as uri, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + pure_sip as pure_sip, + cost as cost +FROM restcomm_incoming_phone_numbers; +DROP TABLE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_incoming_phone_numbers; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016-2.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016-2.sql new file mode 100644 index 0000000000..3d528208bc --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016-2.sql @@ -0,0 +1,11 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #521 +#Date: Mar 11, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#Modify table "restcomm_call_detail_records", add 'instanceid' VARCHAR(255) +ALTER TABLE restcomm_call_detail_records ADD instanceid VARCHAR(255); + +INSERT INTO update_scripts VALUES ('update_script_Mar11_2016-2 for issue #521', NOW()); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016.sql new file mode 100644 index 0000000000..72f7bc712f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Mar11_2016.sql @@ -0,0 +1,11 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #923 +#Date: Mar 11, 2016 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#Modify table "restcomm_instance_id", add 'host' VARCHAR(255) +ALTER TABLE restcomm_instance_id ADD host VARCHAR(255); + +INSERT INTO update_scripts VALUES ('update_script_Mar11_2016', NOW()); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov10_2016.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov10_2016.sql new file mode 100644 index 0000000000..ec616c44a4 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov10_2016.sql @@ -0,0 +1,189 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #461, #4 and #87 +#Date: Oct 27 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +SELECT IFNULL(column_name, '') INTO @colName +FROM information_schema.columns +WHERE table_name = 'restcomm_applications' +AND column_name = 'kind'; + +IF @colName = '' THEN + -- ALTER COMMAND GOES HERE -- +#Drop and create again the "restcomm_applications" table +DROP TABLE restcomm_applications; +CREATE TABLE restcomm_applications ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +friendly_name VARCHAR(64) NOT NULL, +account_sid VARCHAR(34) NOT NULL, +api_version VARCHAR(10) NOT NULL, +voice_caller_id_lookup BOOLEAN NOT NULL, +uri MEDIUMTEXT NOT NULL, +rcml_url MEDIUMTEXT, +kind VARCHAR(5) +); +END IF; + +SELECT IFNULL(column_name, '') INTO @colName +FROM information_schema.columns +WHERE table_name = 'restcomm_available_phone_numbers' +AND column_name = 'cost'; + +IF @colName = '' THEN + -- ALTER COMMAND GOES HERE -- +#Modify table "restcomm_available_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_available_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + friendly_name, + phone_number, + lata, + rate_center, + latitude, + longitude, + region, + postal_code, + iso_country, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + cost +) +SELECT + friendly_name as friendly_name, + phone_number as phone_number, + lata as lata, + rate_center as rate_center, + latitude as latitude, + region as region, + postal_code as postal_code, + iso_country as iso_country, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + cost as cost +FROM restcomm_available_phone_numbers; +DROP TABLE restcomm_available_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_available_phone_numbers; +END IF; + +SELECT IFNULL(column_name, '') INTO @colName +FROM information_schema.columns +WHERE table_name = 'restcomm_incoming_phone_numbers' +AND column_name = 'cost'; + +IF @colName = '' THEN + -- ALTER COMMAND GOES HERE -- +#Modify table "restcomm_incoming_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + friendly_name, + account_sid, + phone_number, + api_version, + voice_caller_id_lookup, + voice_url, + voice_method, + voice_fallback_url, + voice_fallback_method, + status_callback, + status_callback_method, + voice_application_sid, + sms_url, + sms_method, + sms_fallback_url, + sms_fallback_method, + sms_application_sid, + uri, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + pure_sip, + cost +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + friendly_name as friendly_name, + account_sid as account_sid, + phone_number as phone_number, + api_version as api_version, + voice_caller_id_lookup as voice_caller_id_lookup, + voice_url as voice_url, + voice_method as voice_method, + voice_fallback_url as voice_fallback_url, + voice_fallback_method as voice_fallback_method, + status_callback as status_callback, + status_callback_method as status_callback_method, + voice_application_sid as voice_application_sid, + sms_url as sms_url, + sms_method as sms_method, + sms_fallback_url as sms_fallback_url, + sms_fallback_method as sms_fallback_method, + sms_application_sid as sms_application_sid, + uri as uri, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + pure_sip as pure_sip, + cost as cost +FROM restcomm_incoming_phone_numbers; +DROP TABLE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_incoming_phone_numbers; +END IF; + +SELECT IFNULL(column_name, '') INTO @colName +FROM information_schema.columns +WHERE table_name = 'restcomm_registrations' +AND column_name = 'webrtc'; + +IF @colName = '' THEN + -- ALTER COMMAND GOES HERE -- +#Modify table "restcomm_incoming_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_registrations; +ALTER TABLE temp_table ADD webrtc BOOLEAN NOT NULL default false; +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + date_expires, + address_of_record, + display_name, + user_agent, + ttl, + location, + webrtc +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + date_expires as date_expires, + address_of_record as address_of_record, + display_name as display_name, + user_agent as user_agent, + ttl as ttl, + location as location, + FALSE as webrtc +FROM restcomm_registrations; +DROP TABLE restcomm_registrations; +ALTER TABLE temp_table RENAME restcomm_registrations; +END IF; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov2_2015.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov2_2015.sql new file mode 100644 index 0000000000..26c5134bf0 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Nov2_2015.sql @@ -0,0 +1,171 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #461, #4 and #87 +#Date: Oct 27 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +#Drop and create again the "restcomm_applications" table +DROP TABLE restcomm_applications; +CREATE TABLE restcomm_applications ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +friendly_name VARCHAR(64) NOT NULL, +account_sid VARCHAR(34) NOT NULL, +api_version VARCHAR(10) NOT NULL, +voice_caller_id_lookup BOOLEAN NOT NULL, +uri MEDIUMTEXT NOT NULL, +rcml_url MEDIUMTEXT, +kind VARCHAR(5) +); + +#Modify table "restcomm_available_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_available_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + friendly_name, + phone_number, + lata, + rate_center, + latitude, + longitude, + region, + postal_code, + iso_country, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + cost +) +SELECT + friendly_name as friendly_name, + phone_number as phone_number, + lata as lata, + rate_center as rate_center, + latitude as latitude, + region as region, + postal_code as postal_code, + iso_country as iso_country, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + cost as cost +FROM restcomm_available_phone_numbers; +DROP TABLE restcomm_available_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_available_phone_numbers; + +#Modify table "restcomm_incoming_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + friendly_name, + account_sid, + phone_number, + api_version, + voice_caller_id_lookup, + voice_url, + voice_method, + voice_fallback_url, + voice_fallback_method, + status_callback, + status_callback_method, + voice_application_sid, + sms_url, + sms_method, + sms_fallback_url, + sms_fallback_method, + sms_application_sid, + uri, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + pure_sip, + cost +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + friendly_name as friendly_name, + account_sid as account_sid, + phone_number as phone_number, + api_version as api_version, + voice_caller_id_lookup as voice_caller_id_lookup, + voice_url as voice_url, + voice_method as voice_method, + voice_fallback_url as voice_fallback_url, + voice_fallback_method as voice_fallback_method, + status_callback as status_callback, + status_callback_method as status_callback_method, + voice_application_sid as voice_application_sid, + sms_url as sms_url, + sms_method as sms_method, + sms_fallback_url as sms_fallback_url, + sms_fallback_method as sms_fallback_method, + sms_application_sid as sms_application_sid, + uri as uri, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + pure_sip as pure_sip, + cost as cost +FROM restcomm_incoming_phone_numbers; +DROP TABLE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_incoming_phone_numbers; + +CREATE TABLE restcomm_registrations ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +date_expires DATETIME NOT NULL, +address_of_record MEDIUMTEXT NOT NULL, +display_name VARCHAR(255), +user_name VARCHAR(64) NOT NULL, +user_agent MEDIUMTEXT, +ttl INT NOT NULL, +location MEDIUMTEXT NOT NULL, +webrtc BOOLEAN NOT NULL DEFAULT FALSE +); + +#Modify table "restcomm_incoming_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_registrations; +ALTER TABLE temp_table ADD webrtc BOOLEAN NOT NULL default false; +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + date_expires, + address_of_record, + display_name, + user_agent, + ttl, + location, + webrtc +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + date_expires as date_expires, + address_of_record as address_of_record, + display_name as display_name, + user_agent as user_agent, + ttl as ttl, + location as location, + FALSE as webrtc +FROM restcomm_registrations; +DROP TABLE restcomm_registrations; +ALTER TABLE temp_table RENAME restcomm_registrations; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Oct26_2015.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Oct26_2015.sql new file mode 100644 index 0000000000..72c47392a4 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/changelog_depreciated/mariadb/update_script_Oct26_2015.sql @@ -0,0 +1,127 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #461, #4 and #87 +#Date: Oct 27 +#Author: George Vagenas + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +#USE restcomm; + +#Drop and create again the "restcomm_applications" table +DROP TABLE restcomm_applications; +CREATE TABLE restcomm_applications ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +friendly_name VARCHAR(64) NOT NULL, +account_sid VARCHAR(34) NOT NULL, +api_version VARCHAR(10) NOT NULL, +voice_caller_id_lookup BOOLEAN NOT NULL, +uri MEDIUMTEXT NOT NULL, +rcml_url MEDIUMTEXT, +kind VARCHAR(5) +); + +#Modify table "restcomm_available_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_available_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + friendly_name, + phone_number, + lata, + rate_center, + latitude, + longitude, + region, + postal_code, + iso_country, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + cost +) +SELECT + friendly_name as friendly_name, + phone_number as phone_number, + lata as lata, + rate_center as rate_center, + latitude as latitude, + region as region, + postal_code as postal_code, + iso_country as iso_country, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + cost as cost +FROM restcomm_available_phone_numbers; +DROP TABLE restcomm_available_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_available_phone_numbers; + +#Modify table "restcomm_incoming_phone_numbers", move column cost to the end of the table schema +CREATE TABLE temp_table LIKE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table DROP cost; +ALTER TABLE temp_table ADD cost VARCHAR(10); +INSERT INTO temp_table +( + sid, + date_created, + date_updated, + friendly_name, + account_sid, + phone_number, + api_version, + voice_caller_id_lookup, + voice_url, + voice_method, + voice_fallback_url, + voice_fallback_method, + status_callback, + status_callback_method, + voice_application_sid, + sms_url, + sms_method, + sms_fallback_url, + sms_fallback_method, + sms_application_sid, + uri, + voice_capable, + sms_capable, + mms_capable, + fax_capable, + pure_sip, + cost +) SELECT + sid as sid, + date_created as date_created, + date_updated as date_updated, + friendly_name as friendly_name, + account_sid as account_sid, + phone_number as phone_number, + api_version as api_version, + voice_caller_id_lookup as voice_caller_id_lookup, + voice_url as voice_url, + voice_method as voice_method, + voice_fallback_url as voice_fallback_url, + voice_fallback_method as voice_fallback_method, + status_callback as status_callback, + status_callback_method as status_callback_method, + voice_application_sid as voice_application_sid, + sms_url as sms_url, + sms_method as sms_method, + sms_fallback_url as sms_fallback_url, + sms_fallback_method as sms_fallback_method, + sms_application_sid as sms_application_sid, + uri as uri, + voice_capable as voice_capable, + sms_capable as sms_capable, + mms_capable as mms_capable, + fax_capable as fax_capable, + pure_sip as pure_sip, + cost as cost +FROM restcomm_incoming_phone_numbers; +DROP TABLE restcomm_incoming_phone_numbers; +ALTER TABLE temp_table RENAME restcomm_incoming_phone_numbers; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/addConferenceDetailRecord.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/addConferenceDetailRecord.sql new file mode 100644 index 0000000000..b6362c8ca3 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/addConferenceDetailRecord.sql @@ -0,0 +1,23 @@ +DELIMITER // +DROP PROCEDURE IF EXISTS addConferenceDetailRecord; +CREATE PROCEDURE addConferenceDetailRecord( IN in_sid VARCHAR(34), + IN in_date_created DATETIME, + IN in_date_updated DATETIME, + IN in_account_sid VARCHAR(34), + IN in_status VARCHAR(100), + IN in_friendly_name VARCHAR(60), + IN in_api_version VARCHAR(10), + IN in_uri MEDIUMTEXT, + IN in_master_ms_id VARCHAR(34), + IN master_present BOOLEAN ) +BEGIN + IF EXISTS(SELECT * FROM restcomm_conference_detail_records WHERE friendly_name=in_friendly_name AND account_sid=in_account_sid AND status LIKE 'RUNNING%') + THEN + SELECT * FROM restcomm_conference_detail_records WHERE friendly_name=in_friendly_name AND account_sid=in_account_sid AND status LIKE 'RUNNING%'; + ELSE + INSERT INTO restcomm_conference_detail_records (sid, date_created, date_updated, account_sid, status, friendly_name, api_version, uri, master_ms_id, master_present) VALUES (in_sid, in_date_created, in_date_updated, in_account_sid, in_status, in_friendly_name, in_api_version, in_uri, in_master_ms_id, master_present); + + END IF; + +END // +DELIMITER ; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql index 0077e2f46c..8cbbe2857d 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql @@ -1,18 +1,34 @@ CREATE DATABASE IF NOT EXISTS restcomm; USE restcomm; +CREATE TABLE restcomm_organizations ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +domain_name VARCHAR(255) NOT NULL UNIQUE, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +status VARCHAR(16) NOT NULL +); + +CREATE TABLE restcomm_instance_id ( +instance_id VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +host VARCHAR(255) NOT NULL +); + CREATE TABLE restcomm_accounts ( sid VARCHAR(34) NOT NULL PRIMARY KEY, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, email_address MEDIUMTEXT NOT NULL, friendly_name VARCHAR(64) NOT NULL, -account_sid VARCHAR(34), +parent_sid VARCHAR(34), type VARCHAR(8) NOT NULL, status VARCHAR(16) NOT NULL, auth_token VARCHAR(32) NOT NULL, role VARCHAR(64) NOT NULL, -uri MEDIUMTEXT NOT NULL +uri MEDIUMTEXT NOT NULL, +organization_sid VARCHAR(34) NOT NULL ); CREATE TABLE restcomm_announcements ( @@ -38,7 +54,8 @@ iso_country VARCHAR(2) NOT NULL, voice_capable BOOLEAN, sms_capable BOOLEAN, mms_capable BOOLEAN, -fax_capable BOOLEAN +fax_capable BOOLEAN, +cost VARCHAR(10) ); CREATE TABLE restcomm_outgoing_caller_ids ( @@ -66,9 +83,9 @@ CREATE TABLE restcomm_incoming_phone_numbers ( sid VARCHAR(34) NOT NULL PRIMARY KEY, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, -friendly_name VARCHAR(64) NOT NULL, +friendly_name VARCHAR(256) NOT NULL, account_sid VARCHAR(34) NOT NULL, -phone_number VARCHAR(15) NOT NULL, +phone_number VARCHAR(30) NOT NULL, api_version VARCHAR(10) NOT NULL, voice_caller_id_lookup BOOLEAN NOT NULL, voice_url MEDIUMTEXT, @@ -87,7 +104,18 @@ uri MEDIUMTEXT NOT NULL, voice_capable BOOLEAN, sms_capable BOOLEAN, mms_capable BOOLEAN, -fax_capable BOOLEAN +fax_capable BOOLEAN, +pure_sip BOOLEAN, +cost VARCHAR(10), +ussd_url MEDIUMTEXT, +ussd_method VARCHAR(4), +ussd_fallback_url MEDIUMTEXT, +ussd_fallback_method VARCHAR(4), +ussd_application_sid VARCHAR(34), +refer_url MEDIUMTEXT, +refer_method VARCHAR(4), +refer_application_sid VARCHAR(34), +organization_sid VARCHAR(34) NOT NULL ); CREATE TABLE restcomm_applications ( @@ -97,42 +125,62 @@ date_updated DATETIME NOT NULL, friendly_name VARCHAR(64) NOT NULL, account_sid VARCHAR(34) NOT NULL, api_version VARCHAR(10) NOT NULL, -voice_url MEDIUMTEXT, -voice_method VARCHAR(4), -voice_fallback_url MEDIUMTEXT, -voice_fallback_method VARCHAR(4), -status_callback MEDIUMTEXT, -status_callback_method VARCHAR(4), voice_caller_id_lookup BOOLEAN NOT NULL, -sms_url MEDIUMTEXT, -sms_method VARCHAR(4), -sms_fallback_url MEDIUMTEXT, -sms_fallback_method VARCHAR(4), -sms_status_callback MEDIUMTEXT, -uri MEDIUMTEXT NOT NULL +uri MEDIUMTEXT NOT NULL, +rcml_url MEDIUMTEXT, +kind VARCHAR(5) ); CREATE TABLE restcomm_call_detail_records ( -sid VARCHAR(34) NOT NULL PRIMARY KEY, -parent_call_sid VARCHAR(34), +sid VARCHAR(1000) NOT NULL PRIMARY KEY, +parent_call_sid VARCHAR(1000), date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, account_sid VARCHAR(34) NOT NULL, -sender VARCHAR(15) NOT NULL, -recipient VARCHAR(15) NOT NULL, +sender VARCHAR(255) NOT NULL, +recipient VARCHAR(64) NOT NULL, phone_number_sid VARCHAR(34), -status VARCHAR(11) NOT NULL, +status VARCHAR(20) NOT NULL, start_time DATETIME, end_time DATETIME, duration INT, price VARCHAR(8), -direction VARCHAR(13) NOT NULL, -answered_by VARCHAR(7), +direction VARCHAR(20) NOT NULL, +answered_by VARCHAR(64), api_version VARCHAR(10) NOT NULL, -forwarded_from VARCHAR(15), -caller_name VARCHAR(30), +forwarded_from VARCHAR(30), +caller_name VARCHAR(50), uri MEDIUMTEXT NOT NULL, -call_path VARCHAR(255) +call_path VARCHAR(255), +ring_duration INT, +instanceid VARCHAR(255), +conference_sid VARCHAR(34), +muted BOOLEAN, +start_conference_on_enter BOOLEAN, +end_conference_on_exit BOOLEAN, +on_hold BOOLEAN, +ms_id VARCHAR(34) +); + +CREATE TABLE restcomm_conference_detail_records ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +account_sid VARCHAR(34) NOT NULL, +status VARCHAR(100) NOT NULL, +friendly_name VARCHAR(1000), +api_version VARCHAR(10) NOT NULL, +uri MEDIUMTEXT NOT NULL, +master_ms_id VARCHAR(34), +master_conference_endpoint_id VARCHAR(1000), +master_present BOOLEAN NOT NULL DEFAULT TRUE, +master_ivr_endpoint_id VARCHAR(1000), +master_ivr_endpoint_session_id VARCHAR(1000), +master_bridge_endpoint_id VARCHAR(1000), +master_bridge_endpoint_session_id VARCHAR(1000), +master_bridge_conn_id VARCHAR(1000), +master_ivr_conn_id VARCHAR(1000), +moderator_present BOOLEAN NOT NULL DEFAULT FALSE ); CREATE TABLE restcomm_clients ( @@ -150,7 +198,8 @@ voice_method VARCHAR(4), voice_fallback_url MEDIUMTEXT, voice_fallback_method VARCHAR(4), voice_application_sid VARCHAR(34), -uri MEDIUMTEXT NOT NULL +uri MEDIUMTEXT NOT NULL, +push_client_identity VARCHAR(34) ); CREATE TABLE restcomm_registrations ( @@ -163,7 +212,11 @@ display_name VARCHAR(255), user_name VARCHAR(64) NOT NULL, user_agent MEDIUMTEXT, ttl INT NOT NULL, -location MEDIUMTEXT NOT NULL +location MEDIUMTEXT NOT NULL, +webrtc BOOLEAN NOT NULL DEFAULT FALSE, +instanceid VARCHAR(255), +isLBPresent BOOLEAN NOT NULL DEFAULT FALSE, +organization_sid VARCHAR(34) NOT NULL ); CREATE TABLE restcomm_short_codes ( @@ -187,10 +240,10 @@ date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, date_sent DATETIME, account_sid VARCHAR(34) NOT NULL, -sender VARCHAR(15) NOT NULL, -recipient VARCHAR(15) NOT NULL, -body VARCHAR(160) NOT NULL, -status VARCHAR(7) NOT NULL, +sender VARCHAR(255) NOT NULL, +recipient VARCHAR(64) NOT NULL, +body VARCHAR(999) NOT NULL, +status VARCHAR(20) NOT NULL, direction VARCHAR(14) NOT NULL, price VARCHAR(8) NOT NULL, api_version VARCHAR(10) NOT NULL, @@ -202,10 +255,12 @@ sid VARCHAR(34) NOT NULL PRIMARY KEY, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, account_sid VARCHAR(34) NOT NULL, -call_sid VARCHAR(34) NOT NULL, +call_sid VARCHAR(1000) NOT NULL, duration DOUBLE NOT NULL, api_version VARCHAR(10) NOT NULL, -uri MEDIUMTEXT NOT NULL +uri MEDIUMTEXT NOT NULL, +file_uri MEDIUMTEXT, +s3_uri MEDIUMTEXT ); CREATE TABLE restcomm_transcriptions ( @@ -226,7 +281,7 @@ sid VARCHAR(34) NOT NULL PRIMARY KEY, date_created DATETIME NOT NULL, date_updated DATETIME NOT NULL, account_sid VARCHAR(34) NOT NULL, -call_sid VARCHAR(34), +call_sid VARCHAR(1000), api_version VARCHAR(10) NOT NULL, log TINYINT NOT NULL, error_code SMALLINT NOT NULL, @@ -271,6 +326,102 @@ ttl INT NOT NULL, uri MEDIUMTEXT NOT NULL ); +CREATE TABLE restcomm_geolocation( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL, +date_executed DATETIME NOT NULL, +account_sid VARCHAR(34) NOT NULL, +source VARCHAR(30), +device_identifier VARCHAR(30) NOT NULL, +geolocation_type VARCHAR(15) NOT NULL, +response_status VARCHAR(30), +cell_id VARCHAR(10), +location_area_code VARCHAR(10), +mobile_country_code INTEGER, +mobile_network_code VARCHAR(3), +network_entity_address BIGINT, +age_of_location_info INTEGER, +device_latitude VARCHAR(15), +device_longitude VARCHAR(15), +accuracy BIGINT, +physical_address VARCHAR(50), +internet_address VARCHAR(50), +formatted_address VARCHAR(200), +location_timestamp DATETIME, +event_geofence_latitude VARCHAR(15), +event_geofence_longitude VARCHAR(15), +radius BIGINT, +geolocation_positioning_type VARCHAR(15), +last_geolocation_response VARCHAR(15), +cause VARCHAR(150), +api_version VARCHAR(10) NOT NULL, +uri MEDIUMTEXT NOT NULL); + +CREATE TABLE update_scripts ( +script VARCHAR(255) NOT NULL, +date_executed DATETIME NOT NULL +); + +CREATE TABLE restcomm_media_servers ( +ms_id INT PRIMARY KEY AUTO_INCREMENT, +local_ip VARCHAR(34) NOT NULL, +local_port INT NOT NULL, +remote_ip VARCHAR(34) NOT NULL UNIQUE, +remote_port INT NOT NULL, +compatibility VARCHAR(34) DEFAULT "rms", +response_timeout VARCHAR(34), +external_address VARCHAR(34) +); + +CREATE TABLE restcomm_media_resource_broker_entity ( +conference_sid VARCHAR(34) NOT NULL, +slave_ms_id VARCHAR(34) NOT NULL, +slave_ms_bridge_ep_id VARCHAR(34), +slave_ms_cnf_ep_id VARCHAR(34), +is_bridged_together BOOLEAN NOT NULL DEFAULT FALSE, +PRIMARY KEY (conference_sid , slave_ms_id) +); + +CREATE TABLE restcomm_extensions_configuration ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +extension VARCHAR(255) NOT NULL, +configuration_data LONGTEXT NOT NULL, +configuration_type VARCHAR(255) NOT NULL, +date_created DATETIME NOT NULL, +date_updated DATETIME, +enabled BOOLEAN NOT NULL DEFAULT TRUE +); + +CREATE TABLE restcomm_profile_associations( +target_sid VARCHAR(34) NOT NULL PRIMARY KEY, +profile_sid VARCHAR(34) NOT NULL, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL +); + +CREATE TABLE restcomm_accounts_extensions ( +account_sid VARCHAR(34) NOT NULL, +extension_sid VARCHAR(34) NOT NULL, +configuration_data LONGTEXT NOT NULL, +PRIMARY KEY (account_sid, extension_sid) +); + +CREATE TABLE restcomm_profiles ( +sid VARCHAR(34) NOT NULL PRIMARY KEY, +document LONGTEXT NOT NULL, +date_created DATETIME NOT NULL, +date_updated DATETIME NOT NULL +); + +INSERT INTO restcomm_organizations VALUES( +"ORafbe225ad37541eba518a74248f0ac4c", +"default.restcomm.com", +Date("2017-04-19"), +Date("2017-04-19"), +"active" +); + INSERT INTO restcomm_accounts VALUES ( "ACae6e420f425248d6a26948c17a9e2acf", Date("2012-04-24"), @@ -282,20 +433,95 @@ null, "uninitialized", "77f8c12cc7b8f8423e5c38b035249166", "Administrator", -"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf"); +"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf", +"ORafbe225ad37541eba518a74248f0ac4c"); + +/* Create demo Applications */ +INSERT INTO restcomm_applications VALUES('AP73926e7113fa4d95981aa96b76eca854','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','rvdCollectVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','voice'); +INSERT INTO restcomm_applications VALUES('AP81cf45088cba4abcac1261385916d582','2015-09-23 06:56:17.977000','2015-09-23 06:56:17.977000','rvdESDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP81cf45088cba4abcac1261385916d582','/restcomm-rvd/services/apps/AP81cf45088cba4abcac1261385916d582/controller','voice'); +INSERT INTO restcomm_applications VALUES('APb70c33bf0b6748f09eaec97030af36f3','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','rvdSayVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APb70c33bf0b6748f09eaec97030af36f3','/restcomm-rvd/services/apps/APb70c33bf0b6748f09eaec97030af36f3/controller','voice'); /* Bind default DID to demo apps */ -INSERT INTO restcomm_incoming_phone_numbers VALUES('PNdd7a0a0248244615978bd5781598e5eb','2013-10-04 17:42:02.500000000','2013-10-04 17:42:02.500000000','234','ACae6e420f425248d6a26948c17a9e2acf','+1234','2012-04-24',FALSE,'/restcomm/demos/hello-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN146638eec1e2415d832785e30d227598','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','235','ACae6e420f425248d6a26948c17a9e2acf','+1235','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PNabf9c98b95d64b26b5993ad52e809566','2013-10-11 14:55:56.670000000','2013-10-11 14:55:56.670000000','236','ACae6e420f425248d6a26948c17a9e2acf','+1236','2012-04-24',FALSE,'/restcomm/demos/gather/hello-gather.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNabf9c98b95d64b26b5993ad52e809566', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN91275300c95547039c3723a1e58b5662','2013-10-31 22:12:19.318000000','2013-10-31 22:12:19.318000000','237','ACae6e420f425248d6a26948c17a9e2acf','+1237','2012-04-24',FALSE,'/restcomm/demos/dial/sip/dial-sip.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN91275300c95547039c3723a1e58b5662', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN0b4201c6c87749f29367e6cf000686cb','2013-11-04 12:14:10.520000000','2013-11-04 12:14:10.520000000','238','ACae6e420f425248d6a26948c17a9e2acf','+1238','2012-04-24',FALSE,'/restcomm/demos/dial/client/dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN0b4201c6c87749f29367e6cf000686cb', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN9f27f81e725640d988486ff15f48ad18','2013-11-04 12:42:11.530000000','2013-11-04 12:42:11.530000000','310','ACae6e420f425248d6a26948c17a9e2acf','+1310','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9f27f81e725640d988486ff15f48ad18', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN3862668c51634d18ae027c63438b4583','2013-11-04 12:42:44.777000000','2013-11-04 12:42:44.777000000','311','ACae6e420f425248d6a26948c17a9e2acf','+1311','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN3862668c51634d18ae027c63438b4583', true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PNc2b81d68a221482ea387b6b4e2cbd9d7','2014-02-17 22:36:58.008000000','2014-02-17 22:36:58.008000000','239','ACae6e420f425248d6a26948c17a9e2acf','+1239','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdSayVerbDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNc2b81d68a221482ea387b6b4e2cbd9d7',true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000000','2014-02-17 22:37:08.709000000','240','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdCollectVerbDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',true, false, false, false); -INSERT INTO restcomm_incoming_phone_numbers VALUES('PNb43ed9e641364277b6432547ff1109e9','2014-02-17 22:37:19.392000000','2014-02-17 22:37:19.392000000','241','ACae6e420f425248d6a26948c17a9e2acf','+1241','2012-04-24',FALSE,'/restcomm-rvd/services/apps/rvdESDemo/controller','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNb43ed9e641364277b6432547ff1109e9',true, false, false, false); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PNdd7a0a0248244615978bd5781598e5eb','2013-10-04 17:42:02.500000000','2013-10-04 17:42:02.500000000','234','ACae6e420f425248d6a26948c17a9e2acf','+1234','2012-04-24',FALSE,'/restcomm/demos/hello-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN146638eec1e2415d832785e30d227598','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','This app plays the Hello World msg and requires Text-to-speech ','ACae6e420f425248d6a26948c17a9e2acf','+1235','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PNabf9c98b95d64b26b5993ad52e809566','2013-10-11 14:55:56.670000000','2013-10-11 14:55:56.670000000','This app uses the collect verb to get user input','ACae6e420f425248d6a26948c17a9e2acf','+1236','2012-04-24',FALSE,'/restcomm/demos/gather/hello-gather.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNabf9c98b95d64b26b5993ad52e809566', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN91275300c95547039c3723a1e58b5662','2013-10-31 22:12:19.318000000','2013-10-31 22:12:19.318000000','This app requires that you configure the sip:username@ipaddress:port','ACae6e420f425248d6a26948c17a9e2acf','+1237','2012-04-24',FALSE,'/restcomm/demos/dial/sip/dial-sip.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN91275300c95547039c3723a1e58b5662', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN0b4201c6c87749f29367e6cf000686cb','2013-11-04 12:14:10.520000000','2013-11-04 12:14:10.520000000','This app calls registered restcomm client Alice ','ACae6e420f425248d6a26948c17a9e2acf','+1238','2012-04-24',FALSE,'/restcomm/demos/dial/client/dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN0b4201c6c87749f29367e6cf000686cb', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN9f27f81e725640d988486ff15f48ad18','2013-11-04 12:42:11.530000000','2013-11-04 12:42:11.530000000','This app join a conf bridge with wait music playing ','ACae6e420f425248d6a26948c17a9e2acf','+1310','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9f27f81e725640d988486ff15f48ad18', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN3862668c51634d18ae027c63438b4583','2013-11-04 12:42:44.777000000','2013-11-04 12:42:44.777000000','This app adds you to a conf bridge as a moderator','ACae6e420f425248d6a26948c17a9e2acf','+1311','2012-04-24',FALSE,'/restcomm/demos/dial/conference/dial-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN3862668c51634d18ae027c63438b4583', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PNc2b81d68a221482ea387b6b4e2cbd9d7','2014-02-17 22:36:58.008000000','2014-02-17 22:36:58.008000000','This makes a call to a basic RVD app ','ACae6e420f425248d6a26948c17a9e2acf','+1239','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','APb70c33bf0b6748f09eaec97030af36f3',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNc2b81d68a221482ea387b6b4e2cbd9d7',true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000000','2014-02-17 22:37:08.709000000','This is an IVR app that maps user input to specific action','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP73926e7113fa4d95981aa96b76eca854',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PNb43ed9e641364277b6432547ff1109e9','2014-02-17 22:37:19.392000000','2014-02-17 22:37:19.392000000','RVD external services app, customer ID 1 or 2 ','ACae6e420f425248d6a26948c17a9e2acf','+1241','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP81cf45088cba4abcac1261385916d582',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNb43ed9e641364277b6432547ff1109e9',true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN78341988ed59478d89a37bd820d94fb8','2017-02-08 11:11:23.948000000','2017-02-08 11:11:23.948000000','This app plays the video demonstration and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1242','2012-04-24',FALSE,'/restcomm/demos/video-play.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN78341988ed59478d89a37bd820d94fb8',true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN9154cd100e894cccb9846542b831f8f0','2017-03-08 04:29:30.827000000','2017-03-08 04:29:30.827000000','This app records a video message and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1243','2012-04-24',FALSE,'/restcomm/demos/video-record.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN9154cd100e894cccb9846542b831f8f0', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN268b3f55d3a84a70aae8b78bde3443b5','2017-04-13 22:03:27.925000000','2017-04-13 22:03:27.925000000','This app joins a video conf bridge with wait music playing and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1244','2012-04-24',FALSE,'/restcomm/demos/video-conference.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN268b3f55d3a84a70aae8b78bde3443b5', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PNa956a87b060b4b93bf432fce19fe79bf','2017-04-13 22:04:04.258000000','2017-04-13 22:04:04.258000000','This app adds you to a video conf bridge as a moderator and requires XMS media server','ACae6e420f425248d6a26948c17a9e2acf','+1245','2012-04-24',FALSE,'/restcomm/demos/video-conference-moderator.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNa956a87b060b4b93bf432fce19fe79bf', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); +INSERT INTO restcomm_incoming_phone_numbers VALUES('PN5eadc8c3b26a495a842bbff6aecc9f6c','2017-09-29 19:34:10.679000000','2017-09-29 19:34:10.679000000','This app calls registered restcomm client Alice using XMS for video','ACae6e420f425248d6a26948c17a9e2acf','+1246','2012-04-24',FALSE,'/restcomm/demos/video-dial-client.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN5eadc8c3b26a495a842bbff6aecc9f6c', true, false, false, false, true, 0.0, null, null, null, null, null, null, null, null, 'ORafbe225ad37541eba518a74248f0ac4c'); /* Create demo clients */ -INSERT INTO restcomm_clients VALUES('CLa2b99142e111427fbb489c3de357f60a','2013-11-04 12:52:44.144000000','2013-11-04 12:52:44.144000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','alice','alice','1234',1,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a'); -INSERT INTO restcomm_clients VALUES('CL3003328d0de04ba68f38de85b732ed56','2013-11-04 16:33:39.248000000','2013-11-04 16:33:39.248000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','bob','bob','1234',1,NULL,'POST',NULL,'POST',NULL,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56'); +INSERT INTO restcomm_clients VALUES('CLa2b99142e111427fbb489c3de357f60a','2013-11-04 12:52:44.144000000','2013-11-04 12:52:44.144000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','alice','alice','1234',1,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a', NULL); +INSERT INTO restcomm_clients VALUES('CL3003328d0de04ba68f38de85b732ed56','2013-11-04 16:33:39.248000000','2013-11-04 16:33:39.248000000','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','bob','bob','1234',1,NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56', NULL); + +/* Create index on restcomm_call_detail_records on conference_sid column */ +CREATE INDEX idx_cdr_conference_sid ON restcomm_call_detail_records (conference_sid); + +/* Create index on restcomm_call_detail_records on conference_sid column */ +CREATE INDEX idx_cdr_conference_status ON restcomm_conference_detail_records (status); + +DELIMITER // +DROP PROCEDURE IF EXISTS addConferenceDetailRecord; +CREATE PROCEDURE addConferenceDetailRecord( IN in_sid VARCHAR(34), + IN in_date_created DATETIME, + IN in_date_updated DATETIME, + IN in_account_sid VARCHAR(34), + IN in_status VARCHAR(100), + IN in_friendly_name VARCHAR(60), + IN in_api_version VARCHAR(10), + IN in_uri MEDIUMTEXT, + IN in_master_ms_id VARCHAR(34), + IN master_present BOOLEAN ) +BEGIN + IF EXISTS(SELECT * FROM restcomm_conference_detail_records WHERE friendly_name=in_friendly_name AND account_sid=in_account_sid AND status LIKE 'RUNNING%') + THEN + SELECT * FROM restcomm_conference_detail_records WHERE friendly_name=in_friendly_name AND account_sid=in_account_sid AND status LIKE 'RUNNING%'; + ELSE + INSERT INTO restcomm_conference_detail_records (sid, date_created, date_updated, account_sid, status, friendly_name, api_version, uri, master_ms_id, master_present) VALUES (in_sid, in_date_created, in_date_updated, in_account_sid, in_status, in_friendly_name, in_api_version, in_uri, in_master_ms_id, master_present); + + END IF; + +END // +DELIMITER ; + +DELIMITER // +DROP PROCEDURE IF EXISTS completeConferenceDetailRecord; +CREATE PROCEDURE completeConferenceDetailRecord + (IN in_sid VARCHAR(100) + ,IN in_status VARCHAR(100) + ,IN in_slave_ms_id VARCHAR(100) + ,IN in_date_updated TIMESTAMP + ,IN amIMaster BOOLEAN + ,OUT completed BOOLEAN) + +BEGIN + +START TRANSACTION; + SET completed=FALSE; + IF(amIMaster) THEN + UPDATE restcomm_conference_detail_records SET restcomm_conference_detail_records.master_present=FALSE,restcomm_conference_detail_records.date_updated=in_date_updated WHERE restcomm_conference_detail_records.sid=in_sid; + IF NOT EXISTS (SELECT restcomm_media_resource_broker_entity.conference_sid,restcomm_media_resource_broker_entity.slave_ms_id,restcomm_media_resource_broker_entity.slave_ms_bridge_ep_id,restcomm_media_resource_broker_entity.slave_ms_cnf_ep_id,restcomm_media_resource_broker_entity.is_bridged_together FROM restcomm_media_resource_broker_entity WHERE conference_sid=in_sid ) THEN + UPDATE restcomm_conference_detail_records SET status=in_status,date_updated=in_date_updated WHERE sid=in_sid; + SET completed=TRUE; + END IF; + ELSE + DELETE FROM restcomm_media_resource_broker_entity WHERE conference_sid=in_sid AND slave_ms_id=in_slave_ms_id; + IF NOT(SELECT master_present FROM restcomm_conference_detail_records WHERE sid=in_sid) THEN + IF NOT EXISTS(SELECT restcomm_media_resource_broker_entity.conference_sid,restcomm_media_resource_broker_entity.slave_ms_id,restcomm_media_resource_broker_entity.slave_ms_bridge_ep_id,restcomm_media_resource_broker_entity.slave_ms_cnf_ep_id,restcomm_media_resource_broker_entity.is_bridged_together FROM restcomm_media_resource_broker_entity WHERE conference_sid=in_sid ) THEN + UPDATE restcomm_conference_detail_records SET status=in_status,date_updated=in_date_updated WHERE sid=in_sid; + SET completed=TRUE; + END IF; + END IF; + END IF; +COMMIT; + +END // +DELIMITER ; diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/accounts.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/accounts.xml index 7aa45ed3a0..aa1840023b 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/accounts.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/accounts.xml @@ -4,10 +4,10 @@ INSERT INTO restcomm_accounts (sid, date_created, date_updated, - email_address, friendly_name, account_sid, type, status, auth_token, - role, uri) + email_address, friendly_name, parent_sid, type, status, auth_token, + role, uri, organization_sid) VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, - #{account_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}); + #{parent_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}, #{organization_sid}); - + SELECT * FROM restcomm_accounts WHERE parent_sid=#{parent_sid}; + + + @@ -35,7 +39,15 @@ UPDATE restcomm_accounts SET date_updated=#{date_updated}, email_address=#{email_address}, friendly_name=#{friendly_name}, - type=#{type}, status=#{status}, auth_token=#{auth_token}, role=#{role} + type=#{type}, status=#{status}, auth_token=#{auth_token}, role=#{role}, + organization_sid=#{organization_sid} WHERE sid=#{sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/announcements.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/announcements.xml index 712f736c06..826ad59185 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/announcements.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/announcements.xml @@ -20,4 +20,8 @@ DELETE FROM restcomm_announcements WHERE sid=#{sid}; + + + DELETE FROM restcomm_announcements WHERE account_sid=#{account_sid}; + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/applications.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/applications.xml index ce707c4336..9ed3309469 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/applications.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/applications.xml @@ -6,19 +6,43 @@ INSERT INTO restcomm_applications (sid, date_created, date_updated, friendly_name, account_sid, api_version, - voice_url, voice_method, voice_fallback_url, voice_fallback_method, status_callback, status_callback_method, - voice_caller_id_lookup, sms_url, sms_method, sms_fallback_url, sms_fallback_method, sms_status_callback, uri) - VALUES (#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{api_version}, #{voice_url}, #{voice_method}, - #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, #{voice_caller_id_lookup}, - #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_status_callback}, #{uri}); + voice_caller_id_lookup, uri, rcml_url, kind) + VALUES (#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{api_version}, #{voice_caller_id_lookup}, + #{uri}, #{rcml_url}, #{kind}); + + + + @@ -30,10 +54,8 @@ - UPDATE restcomm_applications SET friendly_name=#{friendly_name}, voice_url=#{voice_url}, voice_method=#{voice_method}, - voice_fallback_url=#{voice_fallback_url}, voice_fallback_method=#{voice_fallback_method}, status_callback=#{status_callback}, - status_callback_method=#{status_callback_method}, voice_caller_id_lookup=#{voice_caller_id_lookup}, sms_url=#{sms_url}, - sms_method=#{sms_method}, sms_fallback_url=#{sms_fallback_url}, sms_fallback_method=#{sms_fallback_method}, - sms_status_callback=#{sms_status_callback} WHERE sid=#{sid}; + UPDATE restcomm_applications SET friendly_name=#{friendly_name}, date_updated=#{date_updated}, + voice_caller_id_lookup=#{voice_caller_id_lookup}, rcml_url=#{rcml_url}, kind=#{kind} + WHERE sid=#{sid}; diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/available-phone-numbers.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/available-phone-numbers.xml index 193c977840..6eca2b011e 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/available-phone-numbers.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/available-phone-numbers.xml @@ -5,8 +5,8 @@ --> - INSERT INTO restcomm_available_phone_numbers (friendly_name, phone_number, lata, rate_center, latitude, longitude, region, postal_code, iso_country, voice_capable, sms_capable, mms_capable, fax_capable) - VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}, #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}); + INSERT INTO restcomm_available_phone_numbers (friendly_name, phone_number, lata, rate_center, latitude, longitude, region, postal_code, iso_country, voice_capable, sms_capable, mms_capable, fax_capable, cost) + VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}, #{iso_country}, #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{cost}); SELECT * FROM restcomm_call_detail_records WHERE sid=#{sid}; - - - + + + + + + - + SELECT COUNT(*) FROM restcomm_call_detail_records WHERE + + + + account_sid=#{accountSid} + + + + account_sid IN + + #{item} + + + + account_sid='' + + + + AND instanceid like #{instanceid} + AND recipient like #{recipient} @@ -33,17 +59,42 @@ AND parent_call_sid like #{parentCallSid} + + AND conference_sid like #{conferenceSid} + AND start_time >= #{startTime} + + AND end_time <= DATE_ADD(#{endTime},INTERVAL 1 DAY) + - + SELECT * FROM restcomm_call_detail_records AS restcomm_call_detail_records WHERE + + + + account_sid=#{accountSid} + + + + account_sid IN + + #{item} + + + + account_sid='' + + + + AND instanceid like #{instanceid} + AND recipient like #{recipient} @@ -56,14 +107,39 @@ AND parent_call_sid like #{parentCallSid} + + AND conference_sid like #{conferenceSid} + - AND start_time >= #{startTime} order by start_time + AND start_time >= #{startTime} + + + + AND end_time <= DATE_ADD(#{endTime},INTERVAL 1 DAY) - + + order by start_time LIMIT #{limit} OFFSET #{offset} - - + + + + + + + + + + + + + + + + + + + + + DELETE FROM restcomm_call_detail_records WHERE sid=#{sid}; @@ -98,7 +203,18 @@ - UPDATE restcomm_call_detail_records SET date_updated=#{date_updated}, status=#{status}, start_time=#{start_time}, end_time=#{end_time}, duration=#{duration}, - price=#{price}, answered_by=#{answered_by} WHERE sid=#{sid}; + UPDATE + restcomm_call_detail_records + SET date_updated=#{date_updated}, status=#{status}, start_time=#{start_time}, end_time=#{end_time}, duration=#{duration}, + price=#{price}, answered_by=#{answered_by}, forwarded_from=#{forwarded_from}, ring_duration=#{ring_duration}, conference_sid=#{conference_sid}, muted=#{muted}, start_conference_on_enter=#{start_conference_on_enter}, + end_conference_on_exit=#{end_conference_on_exit}, on_hold=#{on_hold}, ms_id=#{ms_id} + WHERE sid=#{sid}; + + + + UPDATE restcomm_call_detail_records + SET status='completed' + WHERE instanceid=#{instanceid} AND (UPPER(status) = ('IN_PROGRESS') OR + UPPER(status) = ('IN-PROGRESS') OR UPPER(status) = ('RINGING') OR UPPER(status) = ('QUEUED')); diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/clients.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/clients.xml index ac3d7d5796..59a310d60c 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/clients.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/clients.xml @@ -6,23 +6,27 @@ INSERT INTO restcomm_clients (sid, date_created, date_updated, account_sid, api_version, friendly_name, login, password, - status, voice_url, voice_method, voice_fallback_url, voice_fallback_method, voice_application_sid, uri) VALUES (#{sid}, + status, voice_url, voice_method, voice_fallback_url, voice_fallback_method, voice_application_sid, uri, push_client_identity) VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{api_version}, #{friendly_name}, #{login}, #{password}, #{status}, #{voice_url}, - #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}); + #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}, #{push_client_identity}); - + SELECT a.* FROM restcomm_clients a LEFT JOIN restcomm_accounts b ON a.account_sid=b.sid WHERE a.login=#{login} and b.organization_sid=#{organization_sid}; + + DELETE FROM restcomm_clients WHERE sid=#{sid}; @@ -34,6 +38,6 @@ UPDATE restcomm_clients SET friendly_name=#{friendly_name}, password=#{password}, status=#{status}, voice_url=#{voice_url}, voice_method=#{voice_method}, voice_fallback_url=#{voice_fallback_url}, voice_fallback_method=#{voice_fallback_method}, - voice_application_sid=#{voice_application_sid} WHERE sid=#{sid}; + voice_application_sid=#{voice_application_sid}, push_client_identity=#{push_client_identity} WHERE sid=#{sid}; diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/conference-detail-records.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/conference-detail-records.xml new file mode 100644 index 0000000000..71d6ec15b1 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/conference-detail-records.xml @@ -0,0 +1,135 @@ + + + + + + + call addConferenceDetailRecord( #{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{friendly_name}, #{api_version}, #{uri}, #{master_ms_id}, #{master_present} ); + + + + + + + + + + + + + + DELETE FROM restcomm_conference_detail_records WHERE sid=#{sid}; + + + DELETE FROM restcomm_conference_detail_records WHERE account_sid=#{account_sid}; + + + UPDATE + restcomm_conference_detail_records + SET status=#{status}, date_updated=#{date_updated} + WHERE sid=#{sid}; + + + UPDATE + restcomm_conference_detail_records + SET + master_conference_endpoint_id=#{master_conference_endpoint_id}, + master_ivr_endpoint_id=#{master_ivr_endpoint_id}, + master_ivr_endpoint_session_id=#{master_ivr_endpoint_session_id}, + master_ivr_conn_id=#{master_ivr_conn_id}, + date_updated=#{date_updated} + WHERE sid=#{sid}; + + + UPDATE + restcomm_conference_detail_records + SET + master_bridge_endpoint_id=#{master_bridge_endpoint_id}, + master_bridge_endpoint_session_id=#{master_bridge_endpoint_session_id}, + master_bridge_conn_id=#{master_bridge_conn_id}, + date_updated=#{date_updated} + WHERE sid=#{sid}; + + + UPDATE + restcomm_conference_detail_records + SET master_present=#{master_present}, date_updated=#{date_updated} + WHERE sid=#{sid}; + + + UPDATE + restcomm_conference_detail_records + SET moderator_present=#{moderator_present}, date_updated=#{date_updated} + WHERE sid=#{sid}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml new file mode 100644 index 0000000000..261c3e385b --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml @@ -0,0 +1,84 @@ + + + + + + + + INSERT INTO restcomm_extensions_configuration (sid, extension, configuration_data, configuration_type, + date_created, date_updated, enabled) VALUES (#{sid}, #{extension}, #{configuration_data}, #{configuration_type}, + #{date_created}, #{date_updated}, #{enabled}); + + + + UPDATE restcomm_extensions_configuration SET configuration_data=#{configuration_data}, configuration_type=#{configuration_type}, date_updated=#{date_updated}, enabled=#{enabled} + WHERE sid=#{sid} + + + + + + + + + + DELETE FROM restcomm_extensions_configuration WHERE sid=#{sid}; + + + + DELETE FROM restcomm_extensions_configuration WHERE extension=#{extension}; + + + + + + + + + + INSERT INTO restcomm_accounts_extensions (account_sid, extension_sid, configuration_data) + VALUES (#{account_sid}, #{extension_sid}, #{configuration_data}); + + + + UPDATE restcomm_accounts_extensions SET configuration_data=#{configuration_data} + WHERE account_sid=#{account_sid} AND extension_sid=#{extension_sid}; + + + + DELETE FROM restcomm_accounts_extensions + WHERE account_sid=#{account_sid} AND extension_sid=#{extension_sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/geolocation.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/geolocation.xml new file mode 100644 index 0000000000..b430715683 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/geolocation.xml @@ -0,0 +1,40 @@ + + + + + + INSERT INTO restcomm_geolocation(sid, date_created, date_updated, date_executed, account_sid, source, device_identifier, + geolocation_type, response_status, cell_id, location_area_code, mobile_country_code, mobile_network_code, + network_entity_address, age_of_location_info, device_latitude, device_longitude, accuracy, physical_address, internet_address, + formatted_address, location_timestamp, event_geofence_latitude, event_geofence_longitude, radius, geolocation_positioning_type, + last_geolocation_response, cause, api_version, uri) VALUES(#{sid}, #{date_created}, #{date_updated}, #{date_executed}, #{account_sid}, + #{source}, #{device_identifier}, #{geolocation_type}, #{response_status}, #{cell_id}, #{location_area_code}, + #{mobile_country_code}, #{mobile_network_code}, #{network_entity_address}, #{age_of_location_info}, #{device_latitude}, #{device_longitude}, + #{accuracy}, #{physical_address}, #{internet_address}, #{formatted_address}, #{location_timestamp}, #{event_geofence_latitude}, + #{event_geofence_longitude}, #{radius}, #{geolocation_positioning_type}, #{last_geolocation_response}, #{cause}, #{api_version}, + #{uri}); + + + + + + + + DELETE FROM restcomm_geolocation WHERE sid=#{sid}; + + + + UPDATE restcomm_geolocation SET date_updated=#{date_updated}, source=#{source}, response_status=#{response_status}, + cell_id=#{cell_id}, location_area_code=#{location_area_code}, mobile_country_code=#{mobile_country_code}, + mobile_network_code=#{mobile_network_code}, network_entity_address=#{network_entity_address}, age_of_location_info=#{age_of_location_info}, + device_latitude=#{device_latitude}, device_longitude=#{device_longitude}, accuracy=#{accuracy}, physical_address=#{physical_address}, + internet_address=#{internet_address}, formatted_address=#{formatted_address}, location_timestamp=#{location_timestamp}, + event_geofence_latitude=#{event_geofence_latitude}, event_geofence_longitude=#{event_geofence_longitude}, + radius=#{radius}, geolocation_positioning_type=#{geolocation_positioning_type}, last_geolocation_response=#{last_geolocation_response}, + cause=#{cause} WHERE sid=#{sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/incoming-phone-numbers.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/incoming-phone-numbers.xml index 60fe47e469..0a0f9d7a82 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/incoming-phone-numbers.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/incoming-phone-numbers.xml @@ -8,48 +8,190 @@ INSERT INTO restcomm_incoming_phone_numbers (sid, date_created, date_updated, friendly_name, account_sid, phone_number, api_version, voice_caller_id_lookup, voice_url, voice_method, voice_fallback_url, voice_fallback_method, status_callback, status_callback_method, voice_application_sid, sms_url, sms_method, sms_fallback_url, sms_fallback_method, sms_application_sid, uri, voice_capable, sms_capable, - mms_capable, fax_capable) VALUES(#{sid}, + mms_capable, fax_capable, pure_sip, cost, ussd_url, ussd_method, ussd_fallback_url, ussd_fallback_method, ussd_application_sid, refer_url, + refer_method, refer_application_sid, organization_sid) VALUES(#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}, - #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}); + #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{pure_sip}, #{cost}, #{ussd_url}, #{ussd_method}, #{ussd_fallback_url}, + #{ussd_fallback_method}, #{ussd_application_sid}, #{refer_url}, #{refer_method}, #{refer_application_sid}, #{organization_sid}); - + - + - + - - + SELECT * FROM restcomm_incoming_phone_numbers; + + + + + + + + + + + DELETE FROM restcomm_incoming_phone_numbers WHERE sid=#{sid}; - + DELETE FROM restcomm_incoming_phone_numbers WHERE account_sid=#{account_sid}; - + UPDATE restcomm_incoming_phone_numbers SET friendly_name=#{friendly_name}, voice_caller_id_lookup=#{voice_caller_id_lookup}, voice_url=#{voice_url}, voice_method=#{voice_method}, voice_fallback_url=#{voice_fallback_url}, voice_fallback_method=#{voice_fallback_method}, status_callback=#{status_callback}, status_callback_method=#{status_callback_method}, voice_application_sid=#{voice_application_sid}, sms_url=#{sms_url}, sms_method=#{sms_method}, - sms_fallback_url=#{sms_fallback_url}, sms_fallback_method=#{sms_fallback_method}, sms_application_sid=#{sms_application_sid}, voice_capable=#{voice_capable}, - sms_capable=#{sms_capable}, mms_capable=#{mms_capable}, fax_capable=#{fax_capable} WHERE sid=#{sid}; + sms_fallback_url=#{sms_fallback_url}, sms_fallback_method=#{sms_fallback_method}, sms_application_sid=#{sms_application_sid}, + voice_capable=#{voice_capable}, + sms_capable=#{sms_capable}, mms_capable=#{mms_capable}, fax_capable=#{fax_capable}, ussd_url=#{ussd_url}, ussd_method=#{ussd_method}, + ussd_fallback_url=#{ussd_fallback_url}, ussd_fallback_method=#{ussd_fallback_method}, + ussd_application_sid=#{ussd_application_sid}, + refer_url=#{refer_url}, refer_method=#{refer_method}, refer_application_sid=#{refer_application_sid}, organization_sid=#{organization_sid} WHERE sid=#{sid}; diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/instanceId.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/instanceId.xml new file mode 100644 index 0000000000..fd011bb6d7 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/instanceId.xml @@ -0,0 +1,25 @@ + + + + + + INSERT INTO restcomm_instance_id (instance_id, host, date_created, date_updated) + VALUES(#{instance_id}, #{host}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE restcomm_instance_id SET date_updated=#{date_updated}, instance_id=#{instance_id} WHERE instance_id=#{instance_id}; + + + + DELETE FROM restcomm_instance_id WHERE instance_id=#{instance_id}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-resource-broker-entity.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-resource-broker-entity.xml new file mode 100644 index 0000000000..f8c5a8a593 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-resource-broker-entity.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO + restcomm_media_resource_broker_entity + (conference_sid, slave_ms_id, slave_ms_bridge_ep_id, slave_ms_cnf_ep_id, + is_bridged_together) + VALUES + (#{conference_sid}, #{slave_ms_id}, #{slave_ms_bridge_ep_id}, #{slave_ms_cnf_ep_id}, + #{is_bridged_together}); + + + + + + + DELETE FROM restcomm_media_resource_broker_entity WHERE conference_sid=#{conferenceSid} AND slave_ms_id=#{slaveMsId}; + + + + UPDATE restcomm_media_resource_broker_entity + SET slave_ms_bridge_ep_id=#{slave_ms_bridge_ep_id}, + slave_ms_cnf_ep_id=#{slave_ms_cnf_ep_id}, is_bridged_together=#{is_bridged_together} + WHERE conference_sid=#{conference_sid} AND slave_ms_id=#{slave_ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-servers.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-servers.xml new file mode 100644 index 0000000000..15f0a99181 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/media-servers.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO restcomm_media_servers (local_ip, local_port, remote_ip, remote_port, compatibility, response_timeout, external_address) + VALUES (#{local_ip}, #{local_port}, #{remote_ip}, #{remote_port}, #{compatibility}, #{response_timeout}, #{external_address}); + + + + + + + + + + DELETE FROM restcomm_media_servers WHERE ms_id=#{ms_id}; + + + + UPDATE restcomm_media_servers + SET local_ip=#{local_ip}, local_port=#{local_port}, remote_ip=#{remote_ip}, remote_port=#{remote_port}, + compatibility=#{compatibility}, response_timeout=#{response_timeout}, external_address=#{external_address} + WHERE ms_id=#{ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/notifications.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/notifications.xml index b1a89bb76e..5ce9dff20f 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/notifications.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/notifications.xml @@ -10,36 +10,118 @@ #{account_sid}, #{call_sid}, #{api_version}, #{log}, #{error_code}, #{more_info}, #{message_text}, #{message_date}, #{request_url}, #{request_method}, #{request_variables}, #{response_headers}, #{response_body}, #{uri}); - + - + - + - + - + - + DELETE FROM restcomm_notifications WHERE sid=#{sid}; - + DELETE FROM restcomm_notifications WHERE account_sid=#{account_sid}; - + DELETE FROM restcomm_notifications WHERE call_sid=#{call_sid}; + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/organization.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/organization.xml new file mode 100644 index 0000000000..70a8046960 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/organization.xml @@ -0,0 +1,31 @@ + + + + + + INSERT INTO restcomm_organizations (sid, domain_name, date_created, date_updated, status) + VALUES(#{sid}, #{domain_name}, #{date_created}, #{date_updated}, #{status}); + + + + + + + + + + + + UPDATE restcomm_organizations SET date_updated=#{date_updated}, + domain_name=#{domain_name} + WHERE sid=#{sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile-association.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile-association.xml new file mode 100644 index 0000000000..8173e9e45f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile-association.xml @@ -0,0 +1,46 @@ + + + + + + INSERT INTO restcomm_profile_associations (profile_sid, target_sid, date_created, date_updated) + VALUES(#{profile_sid}, #{target_sid}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE restcomm_profile_associations SET date_updated=NOW(), + profile_sid=#{profile_sid} + WHERE target_sid=#{target_sid}; + + + + UPDATE restcomm_profile_associations SET date_updated=NOW(), + profile_sid=#{profile_sid} + WHERE profile_sid=#{old_profile_sid}; + + + + DELETE from restcomm_profile_associations + WHERE profile_sid=#{profile_sid}; + + + + DELETE from restcomm_profile_associations + WHERE '1' = '1' + + AND target_sid = #{target_sid} + + + AND profile_sid = #{profile_sid} + + ; + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile.xml new file mode 100644 index 0000000000..34609f1552 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/profile.xml @@ -0,0 +1,28 @@ + + + + + + INSERT INTO restcomm_profiles (sid, document, date_created, date_updated) + VALUES(#{sid, jdbcType=VARCHAR}, #{profileDocument, jdbcType=LONGVARCHAR}, #{dateCreated, jdbcType=TIMESTAMP}, #{dateUpdated, jdbcType=TIMESTAMP}); + + + + + + + + UPDATE restcomm_profiles SET date_updated=#{dateUpdated, jdbcType=TIMESTAMP}, + document=#{profileDocument, jdbcType=LONGVARCHAR} + WHERE sid=#{sid, jdbcType=VARCHAR}; + + + + DELETE from restcomm_profiles + WHERE sid=#{sid, jdbcType=VARCHAR}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/recordings.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/recordings.xml index e8715caf4b..2c99565512 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/recordings.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/recordings.xml @@ -5,27 +5,108 @@ --> - INSERT INTO restcomm_recordings (sid, date_created, date_updated, account_sid, call_sid, duration, api_version, uri) - VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}); + INSERT INTO restcomm_recordings (sid, date_created, date_updated, account_sid, call_sid, duration, api_version, uri, file_uri, s3_uri) + VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}, #{file_uri}, #{s3_uri}); - + + + UPDATE restcomm_recordings + SET date_updated=#{date_updated}, uri=#{uri}, file_uri=#{file_uri}, s3_uri=#{s3_uri} + WHERE sid=#{sid}; + + - + - + + + - + DELETE FROM restcomm_recordings WHERE sid=#{sid}; - + DELETE FROM restcomm_recordings WHERE account_sid=#{account_sid}; + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/registrations.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/registrations.xml index 87905787ae..61be2924b9 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/registrations.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/registrations.xml @@ -6,19 +6,31 @@ INSERT INTO restcomm_registrations (sid, date_created, date_updated, date_expires, address_of_record, display_name, - user_name, user_agent, ttl, location) + user_name, user_agent, ttl, location, webrtc, instanceid, isLBPresent, organization_sid) VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_expires}, #{address_of_record}, #{display_name}, #{user_name}, #{user_agent}, - #{ttl}, #{location}); + #{ttl}, #{location}, #{webrtc}, #{instanceid}, #{isLBPresent}, #{organization_sid}); - + - + SELECT * FROM restcomm_registrations WHERE user_name=#{user_name} and organization_sid=#{organization_sid}; + + + + + + SELECT * FROM restcomm_sms_messages WHERE sid=#{sid}; - + - + DELETE FROM restcomm_sms_messages WHERE sid=#{sid}; - + DELETE FROM restcomm_sms_messages WHERE account_sid=#{account_sid}; - + UPDATE restcomm_sms_messages SET date_sent=#{date_sent}, status=#{status}, price=#{price} WHERE sid=#{sid}; + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/transcriptions.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/transcriptions.xml index 932dafc8bf..3a42870fc0 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/transcriptions.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/transcriptions.xml @@ -8,32 +8,103 @@ INSERT INTO restcomm_transcriptions (sid, date_created, date_updated, account_sid, status, recording_sid, duration, transcription_text, price, uri) VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{recording_sid}, #{duration}, #{transcription_text}, #{price}, #{uri}); - + - + - + - + DELETE FROM restcomm_transcriptions WHERE sid=#{sid}; - + DELETE FROM restcomm_transcriptions WHERE account_sid=#{account_sid}; - + - UPDATE restcomm_transcriptions SET status=#{status} + UPDATE restcomm_transcriptions SET status=#{status} - , transcription_text=#{transcription_text} + , transcription_text=#{transcription_text} WHERE sid=#{sid}; + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/usage.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/usage.xml new file mode 100644 index 0000000000..6f94c1348f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/usage.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/sql/init.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/sql/init.sql deleted file mode 100644 index 0b2e23eb44..0000000000 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/sql/init.sql +++ /dev/null @@ -1,268 +0,0 @@ -CREATE TABLE "restcomm_accounts" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"email_address" LONGVARCHAR NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"account_sid" VARCHAR(34), -"type" VARCHAR(8) NOT NULL, -"status" VARCHAR(16) NOT NULL, -"auth_token" VARCHAR(32) NOT NULL, -"role" VARCHAR(64) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_announcements" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"account_sid" VARCHAR(34), -"gender" VARCHAR(8) NOT NULL, -"language" VARCHAR(16) NOT NULL, -"text" VARCHAR(32) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_available_phone_numbers" ( -"friendly_name" VARCHAR(64) NOT NULL, -"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY, -"lata" SMALLINT, -"rate_center" VARCHAR(32), -"latitude" DOUBLE, -"longitude" DOUBLE, -"region" VARCHAR(2), -"postal_code" INT, -"iso_country" VARCHAR(2) NOT NULL, -"voice_capable" BOOLEAN, -"sms_capable" BOOLEAN, -"mms_capable" BOOLEAN, -"fax_capable" BOOLEAN -); - -CREATE TABLE "restcomm_outgoing_caller_ids" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"phone_number" VARCHAR(15) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_http_cookies" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"comment" LONGVARCHAR, -"domain" LONGVARCHAR, -"expiration_date" DATETIME, -"name" LONGVARCHAR NOT NULL, -"path" LONGVARCHAR, -"value" LONGVARCHAR, -"version" INT -); - -CREATE TABLE "restcomm_incoming_phone_numbers" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"phone_number" VARCHAR(15) NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"voice_caller_id_lookup" BOOLEAN NOT NULL, -"voice_url" LONGVARCHAR, -"voice_method" VARCHAR(4), -"voice_fallback_url" LONGVARCHAR, -"voice_fallback_method" VARCHAR(4), -"status_callback" LONGVARCHAR, -"status_callback_method" VARCHAR(4), -"voice_application_sid" VARCHAR(34), -"sms_url" LONGVARCHAR, -"sms_method" VARCHAR(4), -"sms_fallback_url" LONGVARCHAR, -"sms_fallback_method" VARCHAR(4), -"sms_application_sid" VARCHAR(34), -"uri" LONGVARCHAR NOT NULL, -"voice_capable" BOOLEAN, -"sms_capable" BOOLEAN, -"mms_capable" BOOLEAN, -"fax_capable" BOOLEAN -); - -CREATE TABLE "restcomm_applications" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"voice_url" LONGVARCHAR, -"voice_method" VARCHAR(4), -"voice_fallback_url" LONGVARCHAR, -"voice_fallback_method" VARCHAR(4), -"status_callback" LONGVARCHAR, -"status_callback_method" VARCHAR(4), -"voice_caller_id_lookup" BOOLEAN NOT NULL, -"sms_url" LONGVARCHAR, -"sms_method" VARCHAR(4), -"sms_fallback_url" LONGVARCHAR, -"sms_fallback_method" VARCHAR(4), -"sms_status_callback" LONGVARCHAR, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_call_detail_records" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"parent_call_sid" VARCHAR(34), -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"sender" VARCHAR(15) NOT NULL, -"recipient" VARCHAR(15) NOT NULL, -"phone_number_sid" VARCHAR(34), -"status" VARCHAR(11) NOT NULL, -"start_time" DATETIME, -"end_time" DATETIME, -"duration" INT, -"price" VARCHAR(8), -"direction" VARCHAR(13) NOT NULL, -"answered_by" VARCHAR(7), -"api_version" VARCHAR(10) NOT NULL, -"forwarded_from" VARCHAR(15), -"caller_name" VARCHAR(30), -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_clients" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"login" VARCHAR(64) NOT NULL, -"password" VARCHAR(64) NOT NULL, -"status" INT NOT NULL, -"voice_url" LONGVARCHAR, -"voice_method" VARCHAR(4), -"voice_fallback_url" LONGVARCHAR, -"voice_fallback_method" VARCHAR(4), -"voice_application_sid" VARCHAR(34), -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_registrations" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"date_expires" DATETIME NOT NULL, -"address_of_record" LONGVARCHAR NOT NULL, -"display_name" VARCHAR(255), -"user_name" VARCHAR(64) NOT NULL, -"user_agent" LONGVARCHAR, -"ttl" INT NOT NULL, -"location" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_short_codes" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"friendly_name" VARCHAR(64) NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"short_code" INT NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"sms_url" LONGVARCHAR, -"sms_method" VARCHAR(4), -"sms_fallback_url" LONGVARCHAR, -"sms_fallback_method" VARCHAR(4), -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_sms_messages" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"date_sent" DATETIME, -"account_sid" VARCHAR(34) NOT NULL, -"sender" VARCHAR(15) NOT NULL, -"recipient" VARCHAR(15) NOT NULL, -"body" VARCHAR(160) NOT NULL, -"status" VARCHAR(7) NOT NULL, -"direction" VARCHAR(14) NOT NULL, -"price" VARCHAR(8) NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_recordings" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"call_sid" VARCHAR(34) NOT NULL, -"duration" DOUBLE NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_transcriptions" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"status" VARCHAR(11) NOT NULL, -"recording_sid" VARCHAR(34) NOT NULL, -"duration" DOUBLE NOT NULL, -"transcription_text" LONGVARCHAR NOT NULL, -"price" VARCHAR(8) NOT NULL, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_notifications" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"account_sid" VARCHAR(34) NOT NULL, -"call_sid" VARCHAR(34), -"api_version" VARCHAR(10) NOT NULL, -"log" TINYINT NOT NULL, -"error_code" SMALLINT NOT NULL, -"more_info" LONGVARCHAR NOT NULL, -"message_text" LONGVARCHAR NOT NULL, -"message_date" DATETIME NOT NULL, -"request_url" LONGVARCHAR NOT NULL, -"request_method" VARCHAR(4) NOT NULL, -"request_variables" LONGVARCHAR NOT NULL, -"response_headers" LONGVARCHAR, -"response_body" LONGVARCHAR, -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_sand_boxes" ( -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"pin" VARCHAR(8) NOT NULL, -"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"phone_number" VARCHAR(15) NOT NULL, -"application_sid" VARCHAR(34) NOT NULL, -"api_version" VARCHAR(10) NOT NULL, -"voice_url" LONGVARCHAR, -"voice_method" VARCHAR(4), -"sms_url" LONGVARCHAR, -"sms_method" VARCHAR(4), -"status_callback" LONGVARCHAR, -"status_callback_method" VARCHAR(4), -"uri" LONGVARCHAR NOT NULL -); - -CREATE TABLE "restcomm_gateways" ( -"sid" VARCHAR(34) NOT NULL PRIMARY KEY, -"date_created" DATETIME NOT NULL, -"date_updated" DATETIME NOT NULL, -"friendly_name" VARCHAR(64), -"user_name" VARCHAR(255), -"password" VARCHAR(255), -"proxy" LONGVARCHAR NOT NULL, -"register" BOOLEAN NOT NULL, -"ttl" INT NOT NULL, -"uri" LONGVARCHAR NOT NULL -); diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sip.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sip.xml index 581aaa04f3..c70a1f9219 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sip.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sip.xml @@ -26,6 +26,10 @@ request.method OPTIONS + + request.method + REFER + @@ -52,23 +56,23 @@ - + RestComm RestComm The RestComm Servlet. - org.mobicents.servlet.restcomm.Bootstrapper + org.restcomm.connect.application.Bootstrapper 0 - + SmsService SmsService - VoIP Innovations SMS Service. + SMS Service. - org.mobicents.servlet.restcomm.sms.SmsServiceProxy + org.restcomm.connect.sms.SmsServiceProxy 1 @@ -78,7 +82,7 @@ CallManager The RestComm Call Manager. - org.mobicents.servlet.restcomm.telephony.CallManagerProxy + org.restcomm.connect.telephony.CallManagerProxy 2 @@ -88,18 +92,50 @@ UserAgentManager The RestComm User Agent Manager. - org.mobicents.servlet.restcomm.telephony.ua.UserAgentManagerProxy + org.restcomm.connect.telephony.ua.UserAgentManagerProxy 3 - + ProxyManager ProxyManager The RestComm Proxy Manager. - org.mobicents.servlet.restcomm.telephony.proxy.ProxyManagerProxy + org.restcomm.connect.telephony.proxy.ProxyManagerProxy 4 + + + + org.restcomm.connect.application.Bootstrapper + + + + + org.restcomm.connect.sms.SmsServiceProxy + + + + + org.restcomm.connect.telephony.CallManagerProxy + + + + + org.restcomm.connect.telephony.ua.UserAgentManagerProxy + + + + + org.restcomm.connect.telephony.proxy.ProxyManagerProxy + + + + + org.restcomm.servlets.sip.OVERRIDE_SYSTEM_HEADER_MODIFICATION + + Modifiable + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/accounts.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/accounts.xml index bbdc5f272e..13fc90533f 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/accounts.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/accounts.xml @@ -5,32 +5,43 @@ --> - INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "account_sid", "type", "status", "auth_token", "role", "uri") - VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{account_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}); + INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "parent_sid", "type", "status", "auth_token", "role", "uri", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{parent_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}, #{organization_sid}); - + - + - + - - + SELECT * FROM "restcomm_accounts" WHERE "parent_sid"=#{parent_sid}; - + + + DELETE FROM "restcomm_accounts" WHERE "sid"=#{sid}; - + UPDATE "restcomm_accounts" SET "date_updated"=#{date_updated}, "email_address"=#{email_address}, "friendly_name"=#{friendly_name}, - "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role} WHERE "sid"=#{sid}; + "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role}, "organization_sid"=#{organization_sid} WHERE "sid"=#{sid}; - \ No newline at end of file + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/announcements.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/announcements.xml index 62a5a7bae9..1e4c8c014a 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/announcements.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/announcements.xml @@ -20,4 +20,8 @@ DELETE FROM "restcomm_announcements" WHERE "sid"=#{sid}; + + + DELETE FROM "restcomm_announcements" WHERE "account_sid"=#{account_sid}; + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/applications.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/applications.xml index 81b5edff78..81206d8acc 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/applications.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/applications.xml @@ -1,4 +1,24 @@ + + - INSERT INTO "restcomm_available_phone_numbers" ("friendly_name", "phone_number", "lata", "rate_center", "latitude", "longitude", "region", "postal_code", "iso_country", "voice_capable", "sms_capable", "mms_capable", "fax_capable") - VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}, #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}); + INSERT INTO "restcomm_available_phone_numbers" ("friendly_name", "phone_number", "lata", "rate_center", "latitude", "longitude", "region", "postal_code", "iso_country", "voice_capable", "sms_capable", "mms_capable", "fax_capable", "cost") + VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}, #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{cost}); SELECT * FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; + + + + - + SELECT COUNT(*) FROM "restcomm_call_detail_records" WHERE + + + "account_sid"=#{accountSid} + + + + "account_sid" IN + + #{item} + + + + "account_sid"='' + + + + + AND "instanceid" like #{instanceid} + AND "recipient" like #{recipient} @@ -32,17 +60,43 @@ AND "parent_call_sid" like #{parentCallSid} + + AND "conference_sid" like #{conferenceSid} + AND "start_time" >= #{startTime} + + AND "end_time" <= DATE_ADD(#{endTime},INTERVAL 1 DAY) + + - + SELECT * FROM "restcomm_call_detail_records" AS "restcomm_call_detail_records" WHERE + + + "account_sid"=#{accountSid} + + + + "account_sid" IN + + #{item} + + + + "account_sid"='' + + + + + AND "instanceid" like #{instanceid} + AND "recipient" like #{recipient} @@ -55,14 +109,38 @@ AND "parent_call_sid" like #{parentCallSid} + + AND "conference_sid" like #{conferenceSid} + - AND "start_time" >= #{startTime} order by "start_time" + AND "start_time" >= #{startTime} + + + AND "end_time" <= DATE_ADD(#{endTime},INTERVAL 1 DAY) - + order by "start_time" LIMIT #{limit} OFFSET #{offset} - - + + + + + + + + @@ -80,12 +158,41 @@ + + + + + + + + + + + + + + DELETE FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; @@ -96,7 +203,16 @@ - UPDATE "restcomm_call_detail_records" SET "date_updated"=#{date_updated}, "status"=#{status}, "start_time"=#{start_time}, "end_time"=#{end_time}, "duration"=#{duration}, - "price"=#{price}, "answered_by"=#{answered_by} WHERE "sid"=#{sid}; + UPDATE "restcomm_call_detail_records" + SET "date_updated"=#{date_updated}, "status"=#{status}, "start_time"=#{start_time}, "end_time"=#{end_time}, "duration"=#{duration}, + "price"=#{price}, "answered_by"=#{answered_by}, "forwarded_from"=#{forwarded_from}, "ring_duration"=#{ring_duration}, "conference_sid"=#{conference_sid}, "muted"=#{muted}, "start_conference_on_enter"=#{start_conference_on_enter}, + "end_conference_on_exit"=#{end_conference_on_exit}, "on_hold"=#{on_hold}, "ms_id"=#{ms_id} + WHERE "sid"=#{sid}; + + + UPDATE "restcomm_call_detail_records" + SET "status"='completed' + WHERE "instanceid"=#{instanceid} AND (UPPER("status") = ('IN_PROGRESS') OR + UPPER("status") = ('IN-PROGRESS') OR UPPER("status") = ('RINGING') OR UPPER("status") = ('QUEUED')); \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/clients.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/clients.xml index c52b4c780d..cb4fff1d83 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/clients.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/clients.xml @@ -6,23 +6,27 @@ INSERT INTO "restcomm_clients" ("sid", "date_created", "date_updated", "account_sid", "api_version", "friendly_name", "login", "password", - "status", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "voice_application_sid", "uri") VALUES (#{sid}, + "status", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "voice_application_sid", "uri", "push_client_identity") VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{api_version}, #{friendly_name}, #{login}, #{password}, #{status}, #{voice_url}, - #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}); + #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}, #{push_client_identity}); - + SELECT "a_clients".* FROM "restcomm_clients" "a_clients" LEFT JOIN "restcomm_accounts" "b_accounts" ON "a_clients"."account_sid" = "b_accounts"."sid" WHERE "a_clients"."login"=#{login} and "b_accounts"."organization_sid"=#{organization_sid}; + + DELETE FROM "restcomm_clients" WHERE "sid"=#{sid}; @@ -34,6 +38,6 @@ UPDATE "restcomm_clients" SET "friendly_name"=#{friendly_name}, "password"=#{password}, "status"=#{status}, "voice_url"=#{voice_url}, "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, - "voice_application_sid"=#{voice_application_sid} WHERE "sid"=#{sid}; + "voice_application_sid"=#{voice_application_sid}, "push_client_identity"=#{push_client_identity} WHERE "sid"=#{sid}; \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/conference-detail-records.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/conference-detail-records.xml new file mode 100644 index 0000000000..93d2467d0f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/conference-detail-records.xml @@ -0,0 +1,137 @@ + + + + + + + INSERT INTO "restcomm_conference_detail_records" ("sid", "date_created", "date_updated", "account_sid", "status", "friendly_name", "api_version", "uri", "master_ms_id", "master_present") VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{friendly_name}, #{api_version}, #{uri}, #{master_ms_id}, #{master_present}); + + + + + + + + + + + + + + DELETE FROM "restcomm_conference_detail_records" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_conference_detail_records" WHERE "account_sid"=#{account_sid}; + + + + UPDATE + "restcomm_conference_detail_records" + SET "status"=#{status}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET + "master_conference_endpoint_id"=#{master_conference_endpoint_id}, + "master_ivr_endpoint_id"=#{master_ivr_endpoint_id}, + "master_ivr_endpoint_session_id"=#{master_ivr_endpoint_session_id}, + "master_ivr_conn_id"=#{master_ivr_conn_id}, + "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET + "master_bridge_endpoint_id"=#{master_bridge_endpoint_id}, + "master_bridge_endpoint_session_id"=#{master_bridge_endpoint_session_id}, + "master_bridge_conn_id"=#{master_bridge_conn_id}, + "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET "master_present"=#{master_present}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET "moderator_present"=#{moderator_present}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml new file mode 100644 index 0000000000..b20ac5233b --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + INSERT INTO "restcomm_extensions_configuration" ("sid", "extension", "configuration_data", "configuration_type", + "date_created", "date_updated", "enabled") VALUES (#{sid}, #{extension}, #{configuration_data}, #{configuration_type}, + #{date_created}, #{date_updated}, #{enabled}); + + + + UPDATE "restcomm_extensions_configuration" SET "configuration_data"=#{configuration_data}, "configuration_type"=#{configuration_type}, "date_updated"=#{date_updated}, "enabled"=#{enabled} + WHERE "sid"=#{sid} + + + + + + + + + + DELETE FROM "restcomm_extensions_configuration" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_extensions_configuration" WHERE "extension"=#{extension}; + + + + + + + + + + INSERT INTO "restcomm_accounts_extensions" ("account_sid", "extension_sid", "configuration_data") + VALUES (#{account_sid}, #{extension_sid}, #{configuration_data}); + + + + UPDATE "restcomm_accounts_extensions" SET "configuration_data"=#{configuration_data} + WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid}; + + + + DELETE FROM "restcomm_accounts_extensions" + WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/geolocation.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/geolocation.xml new file mode 100644 index 0000000000..1b46e5dd2f --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/geolocation.xml @@ -0,0 +1,40 @@ + + + + + + INSERT INTO "restcomm_geolocation"("sid", "date_created", "date_updated", "date_executed", "account_sid", "source", "device_identifier", + "geolocation_type", "response_status", "cell_id", "location_area_code", "mobile_country_code", "mobile_network_code", + "network_entity_address", "age_of_location_info", "device_latitude", "device_longitude", "accuracy", "physical_address", "internet_address", + "formatted_address", "location_timestamp", "event_geofence_latitude", "event_geofence_longitude", "radius", "geolocation_positioning_type", + "last_geolocation_response", "cause", "api_version", "uri") VALUES(#{sid}, #{date_created}, #{date_updated}, #{date_executed}, #{account_sid}, + #{source}, #{device_identifier}, #{geolocation_type}, #{response_status}, #{cell_id}, #{location_area_code}, + #{mobile_country_code}, #{mobile_network_code}, #{network_entity_address}, #{age_of_location_info}, #{device_latitude}, #{device_longitude}, + #{accuracy}, #{physical_address}, #{internet_address}, #{formatted_address}, #{location_timestamp}, #{event_geofence_latitude}, + #{event_geofence_longitude}, #{radius}, #{geolocation_positioning_type}, #{last_geolocation_response}, #{cause}, #{api_version}, + #{uri}); + + + + + + + + DELETE FROM "restcomm_geolocation" WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_geolocation" SET "date_updated"=#{date_updated}, "source"=#{source}, "response_status"=#{response_status}, + "cell_id"=#{cell_id}, "location_area_code"=#{location_area_code}, "mobile_country_code"=#{mobile_country_code}, + "mobile_network_code"=#{mobile_network_code}, "network_entity_address"=#{network_entity_address}, "age_of_location_info"=#{age_of_location_info}, + "device_latitude"=#{device_latitude}, "device_longitude"=#{device_longitude}, "accuracy"=#{accuracy}, "physical_address"=#{physical_address}, + "internet_address"=#{internet_address}, "formatted_address"=#{formatted_address}, "location_timestamp"=#{location_timestamp}, + "event_geofence_latitude"=#{event_geofence_latitude}, "event_geofence_longitude"=#{event_geofence_longitude}, + "radius"=#{radius}, "geolocation_positioning_type"=#{geolocation_positioning_type}, "last_geolocation_response"=#{last_geolocation_response}, + "cause"=#{cause} WHERE "sid"=#{sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/incoming-phone-numbers.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/incoming-phone-numbers.xml index b083318427..05e90aeb51 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/incoming-phone-numbers.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/incoming-phone-numbers.xml @@ -4,52 +4,199 @@ @author thomas.quintana@telestax.com (Thomas Quintana) --> - - INSERT INTO "restcomm_incoming_phone_numbers" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "phone_number", "api_version", - "voice_caller_id_lookup", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", - "voice_application_sid", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_application_sid", "uri", "voice_capable", "sms_capable", - "mms_capable", "fax_capable") VALUES(#{sid}, - #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, - #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, - #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}, - #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}); - + + INSERT INTO "restcomm_incoming_phone_numbers" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "phone_number", "api_version", + "voice_caller_id_lookup", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", + "voice_application_sid", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_application_sid", "uri", "voice_capable", "sms_capable", + "mms_capable", "fax_capable", "pure_sip", "cost", "ussd_url", "ussd_method", "ussd_fallback_url", "ussd_fallback_method", "ussd_application_sid", "refer_url", "refer_method", "refer_application_sid", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, + #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, + #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}, + #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{pure_sip}, #{cost}, #{ussd_url}, #{ussd_method}, #{ussd_fallback_url}, + #{ussd_fallback_method}, #{ussd_application_sid}, #{refer_url}, #{refer_method}, #{refer_application_sid}, #{organization_sid}); + + + + + + + + + + + + + + - + + - - + - - - - DELETE FROM "restcomm_incoming_phone_numbers" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_incoming_phone_numbers" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_incoming_phone_numbers" SET "friendly_name"=#{friendly_name}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "voice_url"=#{voice_url}, - "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, - "status_callback_method"=#{status_callback_method}, "voice_application_sid"=#{voice_application_sid}, "sms_url"=#{sms_url}, "sms_method"=#{sms_method}, - "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, "sms_application_sid"=#{sms_application_sid}, "voice_capable"=#{voice_capable}, - "sms_capable"=#{sms_capable}, "mms_capable"=#{mms_capable}, "fax_capable"=#{fax_capable} WHERE "sid"=#{sid}; - - \ No newline at end of file + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_incoming_phone_numbers" SET "friendly_name"=#{friendly_name}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "voice_url"=#{voice_url}, + "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, + "status_callback_method"=#{status_callback_method}, "voice_application_sid"=#{voice_application_sid}, "sms_url"=#{sms_url}, "sms_method"=#{sms_method}, + "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, "sms_application_sid"=#{sms_application_sid}, + "voice_capable"=#{voice_capable}, + "sms_capable"=#{sms_capable}, "mms_capable"=#{mms_capable}, "fax_capable"=#{fax_capable}, "ussd_url"=#{ussd_url}, "ussd_method"=#{ussd_method}, + "ussd_fallback_url"=#{ussd_fallback_url}, "ussd_fallback_method"=#{ussd_fallback_method}, "ussd_application_sid"=#{ussd_application_sid}, + "refer_url"=#{refer_url}, "refer_method"=#{refer_method}, "refer_application_sid"=#{refer_application_sid},"organization_sid"=#{organization_sid} WHERE "sid"=#{sid}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/instanceId.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/instanceId.xml new file mode 100644 index 0000000000..87f93bd056 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/instanceId.xml @@ -0,0 +1,25 @@ + + + + + + INSERT INTO "restcomm_instance_id" ("instance_id", "host", "date_created", "date_updated") + VALUES(#{instance_id}, #{host}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE "restcomm_instance_id" SET "date_updated"=#{date_updated}, "instance_id"=#{instance_id} WHERE "instance_id"=#{instance_id}; + + + + DELETE FROM "restcomm_instance_id" WHERE "instance_id"=#{instance_id}; + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-resource-broker-entity.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-resource-broker-entity.xml new file mode 100644 index 0000000000..7ea6a90668 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-resource-broker-entity.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO + "restcomm_media_resource_broker_entity" + ("conference_sid", "slave_ms_id", "slave_ms_bridge_ep_id", "slave_ms_cnf_ep_id", + "is_bridged_together") + VALUES + (#{conference_sid}, #{slave_ms_id}, #{slave_ms_bridge_ep_id}, #{slave_ms_cnf_ep_id}, + #{is_bridged_together}); + + + + + + + DELETE FROM "restcomm_media_resource_broker_entity" WHERE "conference_sid"=#{conferenceSid} AND "slave_ms_id"=#{slaveMsId}; + + + + UPDATE "restcomm_media_resource_broker_entity" + SET "slave_ms_bridge_ep_id"=#{slave_ms_bridge_ep_id}, + "slave_ms_cnf_ep_id"=#{slave_ms_cnf_ep_id}, "is_bridged_together"=#{is_bridged_together} + WHERE "conference_sid"=#{conference_sid} AND "slave_ms_id"=#{slave_ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-servers.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-servers.xml new file mode 100644 index 0000000000..5236ca3d2a --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/media-servers.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO "restcomm_media_servers" ("local_ip", "local_port", "remote_ip", "remote_port", "compatibility", "response_timeout", "external_address") + VALUES (#{local_ip}, #{local_port}, #{remote_ip}, #{remote_port}, #{compatibility}, #{response_timeout}, #{external_address}); + + + + + + + + + + DELETE FROM "restcomm_media_servers" WHERE "ms_id"=#{ms_id}; + + + + UPDATE "restcomm_media_servers" + SET "local_ip"=#{local_ip}, "local_port"=#{local_port}, "remote_ip"=#{remote_ip}, "remote_port"=#{remote_port}, + "compatibility"=#{compatibility}, "response_timeout"=#{response_timeout}, "external_address"=#{external_address} + WHERE "ms_id"=#{ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.rvd/src/main/webapp/protoProjects/_proto_sms/data/.forgit b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/migration.xml similarity index 100% rename from restcomm/restcomm.rvd/src/main/webapp/protoProjects/_proto_sms/data/.forgit rename to restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/migration.xml diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/notifications.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/notifications.xml index b4f814a7c6..3417cb17a7 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/notifications.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/notifications.xml @@ -42,4 +42,88 @@ DELETE FROM "restcomm_notifications" WHERE "call_sid"=#{call_sid}; + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/organization.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/organization.xml new file mode 100644 index 0000000000..15d6a3a4b1 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/organization.xml @@ -0,0 +1,31 @@ + + + + + + INSERT INTO "restcomm_organizations" ("sid", "domain_name", "date_created", "date_updated", "status") + VALUES(#{sid}, #{domain_name}, #{date_created}, #{date_updated}, #{status}); + + + + + + + + + + + + UPDATE "restcomm_organizations" SET "date_updated"=#{date_updated}, + "domain_name"=#{domain_name} + WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile-association.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile-association.xml new file mode 100644 index 0000000000..3b0adf8977 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile-association.xml @@ -0,0 +1,46 @@ + + + + + + INSERT INTO "restcomm_profile_associations" ("profile_sid", "target_sid", "date_created", "date_updated") + VALUES(#{profile_sid}, #{target_sid}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "target_sid"=#{target_sid}; + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "profile_sid"=#{old_profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE "profile_sid"=#{profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE '1' = '1' + + AND "target_sid" = #{target_sid} + + + AND "profile_sid" = #{profile_sid} + + ; + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile.xml new file mode 100644 index 0000000000..b8a9c8a9df --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/profile.xml @@ -0,0 +1,28 @@ + + + + + + INSERT INTO "restcomm_profiles" ("sid", "document", "date_created", "date_updated") + VALUES(#{sid, jdbcType=VARCHAR}, #{profileDocument, jdbcType=LONGVARCHAR}, #{dateCreated, jdbcType=TIMESTAMP}, #{dateUpdated, jdbcType=TIMESTAMP}); + + + + + + + + UPDATE "restcomm_profiles" SET "date_updated"=#{dateUpdated, jdbcType=TIMESTAMP}, + "document"=#{profileDocument, jdbcType=LONGVARCHAR} + WHERE "sid"=#{sid, jdbcType=VARCHAR}; + + + + DELETE from "restcomm_profiles" + WHERE "sid"=#{sid, jdbcType=VARCHAR}; + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/recordings.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/recordings.xml index eb7ea28130..9357b6314d 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/recordings.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/recordings.xml @@ -5,27 +5,108 @@ --> - INSERT INTO "restcomm_recordings" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "duration", "api_version", "uri") - VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}); + INSERT INTO "restcomm_recordings" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "duration", "api_version", "uri", "file_uri", "s3_uri") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}, #{file_uri}, #{s3_uri}); - + + + UPDATE "restcomm_recordings" + SET "date_updated"=#{date_updated}, "uri"=#{uri}, "file_uri"=#{file_uri}, "s3_uri"=#{s3_uri} + WHERE "sid"=#{sid}; + + - + - + + + - + DELETE FROM "restcomm_recordings" WHERE "sid"=#{sid}; - + DELETE FROM "restcomm_recordings" WHERE "account_sid"=#{account_sid}; - \ No newline at end of file + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/registrations.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/registrations.xml index 6227be73d2..a4b70c7264 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/registrations.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/registrations.xml @@ -6,19 +6,31 @@ INSERT INTO "restcomm_registrations" ("sid", "date_created", "date_updated", "date_expires", "address_of_record", "display_name", - "user_name", "user_agent", "ttl", "location") + "user_name", "user_agent", "ttl", "location", "webrtc", "instanceid", "isLBPresent", "organization_sid") VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_expires}, #{address_of_record}, #{display_name}, #{user_name}, #{user_agent}, - #{ttl}, #{location}); + #{ttl}, #{location}, #{webrtc}, #{instanceid}, #{isLBPresent}, #{organization_sid}); - + SELECT * FROM "restcomm_registrations" WHERE "user_name"=#{user_name} and "organization_sid"=#{organization_sid}; + + + + + + + SELECT COUNT(*) FROM "restcomm_sms_messages" WHERE "account_sid"=#{account_sid} + AND "direction" IN ('outbound-api', 'outbound-call', 'outbound-reply') + AND "date_created" >= #{start_time}; + + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/transcriptions.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/transcriptions.xml index 8f3336d740..c92c5feeb5 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/transcriptions.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/transcriptions.xml @@ -36,4 +36,75 @@ WHERE "sid"=#{sid}; + + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/usage.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/usage.xml new file mode 100644 index 0000000000..ff13d4f2d6 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/usage.xml @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/web.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/web.xml index 1e040f2279..296fdad500 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/web.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/web.xml @@ -1,30 +1,38 @@ - + RestComm - - Shiro - org.apache.shiro.web.servlet.IniShiroFilter - - configPath - /WEB-INF/conf/shiro.ini - - - - - Shiro - /2012-04-24/* - - + Jersey com.sun.jersey.spi.container.servlet.ServletContainer + + + com.sun.jersey.spi.container.ContainerResponseFilters + org.restcomm.connect.http.cors.CorsFilter + + + com.sun.jersey.spi.container.ContainerRequestFilters + org.restcomm.connect.http.security.SecurityFilter;org.restcomm.connect.http.filters.BodyLengthFilter + + + com.sun.jersey.spi.container.ResourceFilters + com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory + + + com.sun.jersey.api.json.POJOMappingFeature + true + - + resteasy.scan false - + resteasy.scan.providers false @@ -34,13 +42,34 @@ resteasy.scan.resources false - + Jersey /2012-04-24/* - + index.html + + + + + restAPI + /2012-04-24/* + + + + BASIC + Restcomm realm + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-conference-moderator.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-conference-moderator.xml new file mode 100644 index 0000000000..474671e278 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-conference-moderator.xml @@ -0,0 +1,10 @@ + + + Welcome moderator + You will be connected to the video conference bridge + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-conference.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-conference.xml new file mode 100644 index 0000000000..0dff543166 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-conference.xml @@ -0,0 +1,10 @@ + + + Welcome to the video conference bridge + When moderator joins you will be connected + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-dial-client.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-dial-client.xml new file mode 100644 index 0000000000..f80a81e5be --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-dial-client.xml @@ -0,0 +1,10 @@ + + + + /restcomm/audio/demo-prompt.wav + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-dial-sip.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-dial-sip.xml new file mode 100644 index 0000000000..d6fa4e4d53 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-dial-sip.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-play.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-play.xml new file mode 100644 index 0000000000..cd3724e65b --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-play.xml @@ -0,0 +1,4 @@ + + + /restcomm/video/Dialogic.mp4 + diff --git a/restcomm/restcomm.application/src/main/webapp/demos/video-record.xml b/restcomm/restcomm.application/src/main/webapp/demos/video-record.xml new file mode 100644 index 0000000000..459fe4a7f6 --- /dev/null +++ b/restcomm/restcomm.application/src/main/webapp/demos/video-record.xml @@ -0,0 +1,6 @@ + + + A message of 10 seconds will be recorded after the beep, using the camera and microphone. + + Message recorded with success. + \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/video/Dialogic.mp4 b/restcomm/restcomm.application/src/main/webapp/video/Dialogic.mp4 new file mode 100644 index 0000000000..4e1f49c35b Binary files /dev/null and b/restcomm/restcomm.application/src/main/webapp/video/Dialogic.mp4 differ diff --git a/restcomm/restcomm.asr/pom.xml b/restcomm/restcomm.asr/pom.xml index 9a047d5b4a..cb1b576eab 100644 --- a/restcomm/restcomm.asr/pom.xml +++ b/restcomm/restcomm.asr/pom.xml @@ -1,13 +1,13 @@ 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.asr - restcomm.asr + restcomm-connect.asr + restcomm-connect.asr http://maven.apache.org @@ -39,8 +39,8 @@ - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons ${project.version} diff --git a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrInfo.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrInfo.java similarity index 90% rename from restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrInfo.java rename to restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrInfo.java index 1a6ad79855..8091edf2b9 100644 --- a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrInfo.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrInfo.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +package org.restcomm.connect.asr; import java.util.Set; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrRequest.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrRequest.java similarity index 93% rename from restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrRequest.java rename to restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrRequest.java index 974fb471b3..47df821c88 100644 --- a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrRequest.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrRequest.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +package org.restcomm.connect.asr; import java.io.File; import java.util.Map; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrResponse.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrResponse.java similarity index 90% rename from restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrResponse.java rename to restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrResponse.java index 4f24505552..2ab52cb815 100644 --- a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/AsrResponse.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/AsrResponse.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +package org.restcomm.connect.asr; import java.util.Map; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.patterns.StandardResponse; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.patterns.StandardResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/GetAsrInfo.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/GetAsrInfo.java similarity index 89% rename from restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/GetAsrInfo.java rename to restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/GetAsrInfo.java index e0add18c7e..07db48b442 100644 --- a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/GetAsrInfo.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/GetAsrInfo.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +package org.restcomm.connect.asr; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/ISpeechAsr.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java similarity index 93% rename from restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/ISpeechAsr.java rename to restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java index ef6f71ca66..4473ea2736 100644 --- a/restcomm/restcomm.asr/src/main/java/org/mobicents/servlet/restcomm/asr/ISpeechAsr.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java @@ -17,26 +17,25 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +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.asr/src/test/java/org/mobicents/servlet/restcomm/asr/ISpeechAsrTest.java b/restcomm/restcomm.asr/src/test/java/org/restcomm/connect/asr/ISpeechAsrTest.java similarity index 98% rename from restcomm/restcomm.asr/src/test/java/org/mobicents/servlet/restcomm/asr/ISpeechAsrTest.java rename to restcomm/restcomm.asr/src/test/java/org/restcomm/connect/asr/ISpeechAsrTest.java index 3ce9f501fd..94210f506c 100644 --- a/restcomm/restcomm.asr/src/test/java/org/mobicents/servlet/restcomm/asr/ISpeechAsrTest.java +++ b/restcomm/restcomm.asr/src/test/java/org/restcomm/connect/asr/ISpeechAsrTest.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.asr; +package org.restcomm.connect.asr; import akka.actor.Actor; import akka.actor.ActorRef; diff --git a/restcomm/restcomm.asr/src/test/resources/ispeech.xml b/restcomm/restcomm.asr/src/test/resources/ispeech.xml index 054164d883..83a910243c 100644 --- a/restcomm/restcomm.asr/src/test/resources/ispeech.xml +++ b/restcomm/restcomm.asr/src/test/resources/ispeech.xml @@ -12,6 +12,6 @@ - + 1da57e282a615ddd2661c58d50524486 diff --git a/restcomm/restcomm.commons/.gitignore b/restcomm/restcomm.commons/.gitignore new file mode 100644 index 0000000000..63177e76e3 --- /dev/null +++ b/restcomm/restcomm.commons/.gitignore @@ -0,0 +1,14 @@ +/target/ + +# OS trash +.DS_Store +/target/ +/target/ +/target/ +/target/ +/target/ +/target/ +/target/ +/target/ +.idea/ +.idea/* \ No newline at end of file diff --git a/restcomm/restcomm.commons/.settings/org.eclipse.core.resources.prefs b/restcomm/restcomm.commons/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..29abf99956 --- /dev/null +++ b/restcomm/restcomm.commons/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/restcomm/restcomm.commons/.settings/org.eclipse.m2e.core.prefs b/restcomm/restcomm.commons/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000000..f897a7f1cb --- /dev/null +++ b/restcomm/restcomm.commons/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/restcomm/restcomm.commons/pom.xml b/restcomm/restcomm.commons/pom.xml index 8a827e7f9f..7d1b8ee04c 100644 --- a/restcomm/restcomm.commons/pom.xml +++ b/restcomm/restcomm.commons/pom.xml @@ -1,18 +1,17 @@ - + 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.commons - restcomm.commons - http://maven.apache.org + restcomm-connect.commons + restcomm-connect.commons - Mobicents yyyyMMddHHmm ${maven.build.timestamp} UTF-8 @@ -24,27 +23,27 @@ log4j provided - + joda-time joda-time - + org.scala-lang scala-library - + - com.typesafe.akka - akka-actor_2.10 + com.typesafe.akka + akka-actor_2.10 - + com.typesafe.akka akka-slf4j_2.10 - + com.google.guava guava @@ -54,7 +53,12 @@ org.apache.httpcomponents httpclient - + + + org.apache.httpcomponents + httpasyncclient + + commons-configuration commons-configuration @@ -64,35 +68,65 @@ commons-io commons-io - + org.apache.shiro shiro-core - + javax.mail mail - + + + com.google.code.gson + gson + + junit junit test - + org.scalatest scalatest_2.9.1 - + com.typesafe.akka akka-testkit_2.10 + + + com.amazonaws + aws-java-sdk-s3 + + + org.apache.httpcomponents + httpclient + + + + + + javax.sip + jain-sip-ri + provided + + + + org.mockito + mockito-core + 1.10.19 + test + + - + @@ -120,6 +154,6 @@ - - + + diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Version.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Version.java deleted file mode 100644 index 7d34081674..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Version.java +++ /dev/null @@ -1,140 +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.mobicents.servlet.restcomm; - -import java.io.IOException; -import java.io.InputStream; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Properties; - -import org.apache.log4j.Logger; - -/** - * @author jderruelle - * @author pslegr - * - */ -public class Version { - private static Logger logger = Logger.getLogger(Version.class); - - public static void printVersion() { - if (logger.isInfoEnabled()) { - Properties releaseProperties = new Properties(); - try { - InputStream in = Version.class - .getResourceAsStream("release.properties"); - if (in != null) { - releaseProperties.load(in); - in.close(); - String releaseVersion = releaseProperties - .getProperty("release.version"); - String releaseName = releaseProperties - .getProperty("release.name"); - String releaseDate = releaseProperties - .getProperty("release.date"); - String releaseRevision = releaseProperties - .getProperty("release.revision"); - String releaseDisclaimer = releaseProperties - .getProperty("release.disclaimer"); - if (releaseVersion != null) { - // Follow the EAP Convention - // Release ID: JBoss [EAP] 5.0.1 (build: - // SVNTag=JBPAPP_5_0_1 date=201003301050) - logger.info("Release ID: (" + releaseName - + ") Mobicents Restcomm " + releaseVersion - + " (build: Git Hash=" + releaseRevision - + " date=" + releaseDate + ")"); - logger.info(releaseName + " Mobicents Restcomm " - + releaseVersion + " (build: Git Hash=" - + releaseRevision + " date=" + releaseDate - + ") Started."); - } else { - logger.warn("Unable to extract the version of Mobicents Restcomm currently running"); - } - if (releaseDisclaimer != null) { - logger.info(releaseDisclaimer); - } - } else { - logger.warn("Unable to extract the version of Mobicents Restcomm currently running"); - } - } catch (IOException e) { - logger.warn( - "Unable to extract the version of Mobicents Restcomm currently running", - e); - } - } - } - - public static String getFullVersion() { - Properties releaseProperties = new Properties(); - try { - InputStream in = Version.class - .getResourceAsStream("release.properties"); - if (in != null) { - releaseProperties.load(in); - in.close(); - String releaseVersion = releaseProperties - .getProperty("release.version"); - String releaseName = releaseProperties - .getProperty("release.name"); - String releaseDate = releaseProperties - .getProperty("release.date"); - if(releaseDate.equals("${maven.build.timestamp}")) { - Date date = new Date(); - releaseDate = new SimpleDateFormat("yyyy/MM/dd_HH:mm").format(date); - } - String releaseRevision = releaseProperties - .getProperty("release.revision"); - - return "Release ID: (" + releaseName + ") Restcomm " - + releaseVersion + " (build: Git Hash=" - + releaseRevision + " date=" + releaseDate + ")"; - } - } catch (Exception e) { - logger.warn( - "Unable to extract the version of Mobicents Sip Servlets currently running", - e); - } - return null; - } - - public static String getVersion() { - Properties releaseProperties = new Properties(); - try { - InputStream in = Version.class - .getResourceAsStream("release.properties"); - if (in != null) { - releaseProperties.load(in); - in.close(); - String releaseVersion = releaseProperties - .getProperty("release.version"); - - return releaseVersion; - } - } catch (Exception e) { - logger.warn( - "Unable to extract the version of Mobicents Sip Servlets currently running", - e); - } - return null; - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCache.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCache.java deleted file mode 100644 index 6b213f4bd1..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCache.java +++ /dev/null @@ -1,178 +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.mobicents.servlet.restcomm.cache; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; - -import org.apache.commons.io.FileUtils; -import org.apache.shiro.crypto.hash.Sha256Hash; - -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class DiskCache extends UntypedActor { - - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - - private final String location; - private final String uri; - - public DiskCache(final String location, final String uri, final boolean create) { - super(); - // Format the cache path. - String temp = location; - if (!temp.endsWith("/")) { - temp += "/"; - } - // Create the cache path if specified. - final File path = new File(temp); -// if (create) { -// path.mkdirs(); -// } - - // Make sure the cache path exists and is a directory. - if (!path.exists() || !path.isDirectory()) { -// throw new IllegalArgumentException(location + " is not a valid cache location."); - path.mkdirs(); - } - // Format the cache URI. - this.location = temp; - temp = uri; - if (!temp.endsWith("/")) { - temp += "/"; - } - this.uri = temp; - } - - public DiskCache(final String location, final String uri) { - this(location, uri, false); - } - - private URI cache(final Object message) throws IOException { - final DiskCacheRequest request = (DiskCacheRequest) message; - - if (request.hash() == null) { - if (request.uri().getScheme().equalsIgnoreCase("file")) { - File origFile = new File(request.uri()); - File destFile = new File(location + origFile.getName()); - if (!destFile.exists()) - FileUtils.moveFile(origFile, destFile); - - return URI.create(this.uri + destFile.getName()); - - } else { - // This is a request to cache a URI - String hash = null; - URI uri = null; - if (request.uri().toString().contains("hash")) { - String fragment = request.uri().getFragment(); - hash = fragment.replace("hash=", ""); - String uriStr = ((request.uri().toString()).replace(fragment, "")).replace("#", ""); - uri = URI.create(uriStr); - } else { - uri = request.uri(); - hash = new Sha256Hash(uri.toString()).toHex(); - } - - final String extension = extension(uri).toLowerCase(); - final File path = new File(location + hash + "." + extension); - if (!path.exists()) { - final File tmp = new File(path + "." + "tmp"); - InputStream input = null; - OutputStream output = null; - try { - input = uri.toURL().openStream(); - output = new FileOutputStream(tmp); - final byte[] buffer = new byte[4096]; - int read = 0; - do { - read = input.read(buffer, 0, 4096); - if (read > 0) { - output.write(buffer, 0, read); - } - } while (read != -1); - tmp.renameTo(path); - } finally { - if (input != null) { - input.close(); - } - if (output != null) { - output.close(); - } - } - } - return URI.create(this.uri + hash + "." + extension); - } - } else { - // This is a check cache request - final String extension = "wav"; - final String hash = request.hash(); - final String filename = hash + "." + extension; - File matchedFile = (new File(location)).listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { - // return name.startsWith(hash) && name.endsWith("."+extension); - return name.equalsIgnoreCase(filename); - } - })[0]; - - if (matchedFile.exists()) { - // return URI.create(matchedFile.getAbsolutePath()); - return URI.create(this.uri + filename); - } else { - throw new FileNotFoundException(filename); - } - } - } - - private String extension(final URI uri) { - final String path = uri.getPath(); - return path.substring(path.lastIndexOf(".") + 1); - } - - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - final ActorRef self = self(); - final ActorRef sender = sender(); - if (DiskCacheRequest.class.equals(klass)) { - DiskCacheResponse response = null; - try { - response = new DiskCacheResponse(cache(message)); - } catch (final Exception exception) { - logger.error("Error while chaching", exception); - response = new DiskCacheResponse(exception); - } - sender.tell(response, self); - } - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheResponse.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheResponse.java deleted file mode 100644 index 2772566a16..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheResponse.java +++ /dev/null @@ -1,48 +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.mobicents.servlet.restcomm.cache; - -import java.net.URI; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.patterns.StandardResponse; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class DiskCacheResponse extends StandardResponse { - public DiskCacheResponse(final Throwable cause, final String message) { - super(cause, message); - } - - public DiskCacheResponse(final Throwable cause) { - super(cause); - } - - public DiskCacheResponse(final URI object) { - super(object); - } - - @Override - public String toString() { - return "DiskCacheResponse [" + super.toString() + "]"; - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/Mail.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/Mail.java deleted file mode 100644 index 2d5b75617a..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/Mail.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.mobicents.servlet.restcomm.email; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -@Immutable -public final class Mail { - private final String from; - private final String to; - private final String subject; - private final String body; - - public Mail(final String from, final String to, final String subject, final String body) { - super(); - this.from = from; - this.to = to; - this.subject = subject; - this.body = body; - } - - public String from() { - return from; - } - - public String to() { - return to; - } - - public String subject() { - return subject; - } - - public String body() { - return body; - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/MailMan.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/MailMan.java deleted file mode 100644 index a50c1e48c1..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/email/MailMan.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.mobicents.servlet.restcomm.email; - -import java.util.Properties; - -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; - -import org.apache.commons.configuration.Configuration; - -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; - -public final class MailMan extends UntypedActor { - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - // Email client session. - private final Session session; - - public MailMan(final Configuration configuration) { - super(); - final String host = configuration.getString("host"); - final String user = configuration.getString("user"); - final String password = configuration.getString("password"); - final Properties properties = System.getProperties(); - properties.setProperty("mail.smtp.host", host); - if (user != null && !user.isEmpty()) { - properties.setProperty("mail.user", user); - } - if (password != null && !password.isEmpty()) { - properties.setProperty("mail.password", password); - } - session = Session.getDefaultInstance(properties); - } - - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Mail.class.equals(klass)) { - send(message); - } - } - - private void send(final Object message) { - final Mail mail = (Mail) message; - try { - final InternetAddress from = new InternetAddress(mail.from()); - final InternetAddress to = new InternetAddress(mail.to()); - final MimeMessage email = new MimeMessage(session); - email.setFrom(from); - email.addRecipient(Message.RecipientType.TO, to); - email.setSubject(mail.subject()); - email.setText(mail.body()); - Transport.send(email); - } catch (final MessagingException exception) { - logger.error(exception.getMessage(), exception); - } - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/State.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/State.java deleted file mode 100644 index d835e70164..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/State.java +++ /dev/null @@ -1,83 +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.mobicents.servlet.restcomm.fsm; - -import static com.google.common.base.Preconditions.*; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public class State { - private final Action actionOnEnter; - private final Action actionOnExit; - private final String id; - - public State(final String id, final Action actionOnEnter, final Action actionOnExit) { - super(); - checkNotNull(id, "A state can not have a null value for id."); - this.actionOnEnter = actionOnEnter; - this.actionOnExit = actionOnExit; - this.id = id; - } - - @Override - public boolean equals(final Object object) { - if (object == null) { - return false; - } else if (this == object) { - return true; - } else if (getClass() != object.getClass()) { - return false; - } - final State state = (State) object; - if (!id.equals(state.getId())) { - return false; - } - return true; - } - - public Action getActionOnEnter() { - return actionOnEnter; - } - - public Action getActionOnExit() { - return actionOnExit; - } - - public String getId() { - return id; - } - - @Override - public int hashCode() { - final int prime = 5; - int result = 1; - result = prime * result + id.hashCode(); - return result; - } - - @Override - public String toString() { - return id; - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/UriUtils.java b/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/UriUtils.java deleted file mode 100644 index 0461f36a37..0000000000 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/UriUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.mobicents.servlet.restcomm.util; - -import java.net.URI; -import java.net.URISyntaxException; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * Utility class to manipulate URI. - * @author Henrique Rosa - */ -@ThreadSafe -public final class UriUtils { - - /** - * Default constructor. - */ - private UriUtils() { - super(); - } - - /** - * Resolves a relative URI. - * @param base The base of the URI - * @param uri The relative URI. - * @return The absolute URI - */ - public static URI resolve(final URI base, final URI uri) { - if (base.equals(uri)) { - return uri; - } else { - if (!uri.isAbsolute()) { - return base.resolve(uri); - } else { - return uri; - } - } - } - - /** - * Resolves a relative URI. - * @param address The IP address of the base URI . - * @param port The port of the base URI. - * @param uri The relative URI - * @return The absolute URI - */ - public static URI resolve(final String address, final int port, final URI uri) { - String base = "http://" + address + ":" + port; - try { - return resolve(new URI(base), uri); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Badly formed URI: " + base, e); - } - } -} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Configurable.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Configurable.java similarity index 83% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Configurable.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Configurable.java index 697d73607d..572145d1ec 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/Configurable.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Configurable.java @@ -17,13 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm; +package org.restcomm.connect.commons; import org.apache.commons.configuration.Configuration; +import scala.concurrent.ExecutionContext; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ public interface Configurable { - void configure(Configuration configuration); + void configure(Configuration configuration, Configuration daoManagerConfiguration, ExecutionContext ec); } diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnector.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnector.java new file mode 100644 index 0000000000..a3185b66ae --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnector.java @@ -0,0 +1,55 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.commons; + +/** + * @author gvagenas + * + */ +public class HttpConnector { + private final String scheme; + private final String address; + private final int port; + private final boolean secure; + + public HttpConnector(final String scheme, final String address, final int port, final boolean secure) { + this.scheme = scheme; + this.address = address; + this.port = port; + this.secure = secure; + } + + public String getScheme() { + return scheme; + } + + public String getAddress() { + return address; + } + + public int getPort() { + return port; + } + + public boolean isSecure() { + return secure; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnectorList.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnectorList.java new file mode 100644 index 0000000000..83964553ec --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/HttpConnectorList.java @@ -0,0 +1,39 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.commons; + +import java.util.List; + +/** + * @author gvagenas + * + */ +public class HttpConnectorList { + private final List connectors; + + public HttpConnectorList(final List connectors) { + this.connectors = connectors; + } + + public List getConnectors() { + return connectors; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/LifeCycle.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/LifeCycle.java similarity index 96% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/LifeCycle.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/LifeCycle.java index 9ce6120d2c..fa0a6ce8c6 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/LifeCycle.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/LifeCycle.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm; +package org.restcomm.connect.commons; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/ServiceLocator.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/ServiceLocator.java similarity index 94% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/ServiceLocator.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/ServiceLocator.java index 038ef33c42..86c785415e 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/ServiceLocator.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/ServiceLocator.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm; +package org.restcomm.connect.commons; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Version.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Version.java new file mode 100644 index 0000000000..d4b1574cfe --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/Version.java @@ -0,0 +1,137 @@ +/* + * 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; + +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Properties; + +import org.apache.log4j.Logger; + +/** + * @author jderruelle + * @author pslegr + * @author gvagenas + * + */ +public class Version { + private static Logger logger = Logger.getLogger(Version.class); + private static VersionEntity versionEntity; + + public static void printVersion() { + if (logger.isInfoEnabled()) { + if (versionEntity == null) + versionEntity = generateVersionEntity(); + String releaseVersion = versionEntity.getVersion(); + String releaseName = versionEntity.getName(); + String releaseDate = versionEntity.getDate(); + String releaseRevision = versionEntity.getRevision(); + String releaseDisclaimer = versionEntity.getDisclaimer(); + if (releaseVersion != null) { + // Follow the EAP Convention + // Release ID: JBoss [EAP] 5.0.1 (build: + // SVNTag=JBPAPP_5_0_1 date=201003301050) + logger.info("Release ID: Restcomm-Connect " + releaseVersion + + " (build: Git Hash=" + releaseRevision + + " date=" + releaseDate + ")"); + logger.info(releaseName + " Restcomm-Connect " + + releaseVersion + " (build: Git Hash=" + + releaseRevision + " date=" + releaseDate + + ") Started."); + } else { + logger.warn("Unable to extract the version of Restcomm-Connect currently running"); + } + if (releaseDisclaimer != null) { + logger.info(releaseDisclaimer); + } + } else { + logger.warn("Unable to extract the version of Restcomm-Connect currently running"); + } + } + + private static VersionEntity generateVersionEntity() { + Properties releaseProperties = new Properties(); + try { + InputStream in = Version.class + .getResourceAsStream("release.properties"); + if (in != null) { + releaseProperties.load(in); + in.close(); + String releaseVersion = releaseProperties + .getProperty("release.version"); + String releaseName = releaseProperties + .getProperty("release.name"); + String releaseDate = releaseProperties + .getProperty("release.date"); + String releaseRevision = releaseProperties + .getProperty("release.revision"); + String releaseDisclaimer = releaseProperties + .getProperty("release.disclaimer"); + versionEntity = new VersionEntity(releaseVersion,releaseRevision,releaseName,releaseDate, releaseDisclaimer); + } else { + logger.warn("Unable to extract the version of Restcomm-Connect currently running"); + } + } catch (IOException e) { + logger.warn("Unable to extract the version of Restcomm-Connect currently running",e); + } + return versionEntity; + } + + public static VersionEntity getVersionEntity() { + if (versionEntity != null) { + return versionEntity; + } else { + return generateVersionEntity(); + } + } + + public static String getFullVersion() { + if (versionEntity == null) + versionEntity = generateVersionEntity(); + + String releaseVersion = versionEntity.getVersion(); + String releaseName = versionEntity.getName(); + String releaseDate = versionEntity.getDate(); + if(releaseDate.equals("${maven.build.timestamp}")) { + Date date = new Date(); + releaseDate = new SimpleDateFormat("yyyy/MM/dd_HH:mm").format(date); + } + String releaseRevision = versionEntity.getRevision(); + + return "Release ID: Restcomm-Connect " + + releaseVersion + " (build: Git Hash=" + + releaseRevision + " date=" + releaseDate + ")"; + } + + public static String getVersion() { + if (versionEntity == null) + versionEntity = generateVersionEntity(); + return versionEntity.getVersion(); + } + + public static String getRevision() { + if (versionEntity == null) + versionEntity = generateVersionEntity(); + return versionEntity.getRevision(); + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/VersionEntity.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/VersionEntity.java new file mode 100644 index 0000000000..0b37439e31 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/VersionEntity.java @@ -0,0 +1,64 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.commons; + +/** + * Created by gvagenas on 1/19/16. + * @author gvagenas + */ +public class VersionEntity { + + private final String version; + //Git hash + private final String revision; + private final String name; + private final String date; + private final String disclaimer; + + public VersionEntity(final String version, final String revision, final String name, final String date, final String disclaimer) { + this.version = version; + this.revision = revision; + this.name = name; + this.date = date; + this.disclaimer = disclaimer; + } + + public String getVersion() { + return version; + } + + public String getRevision() { + return revision; + } + + public String getName() { + return name; + } + + public String getDate() { + return date; + } + + public String getDisclaimer() { + return disclaimer; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/RecordingSecurityLevel.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/RecordingSecurityLevel.java new file mode 100644 index 0000000000..d220af2867 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/RecordingSecurityLevel.java @@ -0,0 +1,14 @@ +package org.restcomm.connect.commons.amazonS3; + +/** + * Created by gvagenas on 14/03/2017. + */ +public enum RecordingSecurityLevel { + NONE("none"),REDIRECT("redirect"),SECURE("secure"); + + private final String text; + + private RecordingSecurityLevel(final String text) { + this.text = text; + } +} 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 new file mode 100644 index 0000000000..6b44d9cf03 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/S3AccessTool.java @@ -0,0 +1,228 @@ +/* + * 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.amazonS3; + +import com.amazonaws.AmazonClientException; +import com.amazonaws.AmazonServiceException; +import com.amazonaws.HttpMethod; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Region; +import com.amazonaws.regions.Regions; +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; +import com.amazonaws.services.s3.model.StorageClass; +import org.apache.commons.io.FileUtils; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; + +import javax.activation.MimetypesFileTypeMap; +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; +import java.util.Date; + +/** + * @author gvagenas + * + */ +public class S3AccessTool { + + private static Logger logger = Logger.getLogger(S3AccessTool.class); + + private String accessKey; + private String securityKey; + private String bucketName; + private String folder; + private String bucketRegion; + private boolean reducedRedundancy; + private int minutesToRetainPublicUrl; + private boolean removeOriginalFile; + private boolean testing; + private String testingUrl; + private AmazonS3 s3client; + private int maxDelay; + + public S3AccessTool(final String accessKey, final String securityKey, final String bucketName, final String folder, + final boolean reducedRedundancy, final int minutesToRetainPublicUrl, final boolean removeOriginalFile, + final String bucketRegion, final boolean testing, final String testingUrl) { + this.accessKey = accessKey; + this.securityKey = securityKey; + this.bucketName = bucketName; + this.folder = folder; + this.reducedRedundancy = reducedRedundancy; + this.minutesToRetainPublicUrl = minutesToRetainPublicUrl; + this.removeOriginalFile = removeOriginalFile; + this.bucketRegion = bucketRegion; + this.testing = testing; + this.testingUrl = testingUrl; + this.maxDelay = RestcommConfiguration.getInstance().getMain().getRecordingMaxDelay(); + } + + public AmazonS3 getS3client() { + BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, securityKey); + + if (testing && (!testingUrl.isEmpty() || !testingUrl.equals(""))) { + 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(); + } + + return s3client; + } + + public boolean uploadFile(final String fileToUpload) { + if (s3client == null) { + s3client = getS3client(); + } + if(logger.isInfoEnabled()){ + logger.info("S3 Region: "+bucketRegion.toString()); + } + try { + URI fileUri = URI.create(fileToUpload); + File file = new File(fileUri); + StringBuffer bucket = new StringBuffer(); + bucket.append(bucketName); + if (folder != null && !folder.isEmpty()) + bucket.append("/").append(folder); + if (logger.isInfoEnabled()) { + logger.info("File to upload to S3: " + fileUri.toString()); + } + + //For statistics and logs + DateTime start, end; + double waitDuration; + + if (fileExists(file)) { + start = DateTime.now(); + PutObjectRequest putRequest = new PutObjectRequest(bucket.toString(), file.getName(), file); + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(new MimetypesFileTypeMap().getContentType(file)); + putRequest.setMetadata(metadata); + if (reducedRedundancy) + putRequest.setStorageClass(StorageClass.ReducedRedundancy); + s3client.putObject(putRequest); + + if (removeOriginalFile) { + removeLocalFile(file); + } + end = DateTime.now(); + waitDuration = (end.getMillis() - start.getMillis())/1000; + if (waitDuration > maxDelay || testing) { + if (logger.isInfoEnabled()) { + String msg = String.format("File %s uploaded to S3 successfully. Upload time %,.2f sec", fileUri.toString(), waitDuration); + logger.info(msg); + } + } + return true; + } else { + String msg = String.format("Recording file \"%s\" doesn't exists ",file.getPath()); + logger.error(msg); + return false; + } + } catch (AmazonServiceException ase) { + logger.error("Caught an AmazonServiceException"); + logger.error("Error Message: " + ase.getMessage()); + logger.error("HTTP Status Code: " + ase.getStatusCode()); + logger.error("AWS Error Code: " + ase.getErrorCode()); + logger.error("Error Type: " + ase.getErrorType()); + logger.error("Request ID: " + ase.getRequestId()); + return false; + } catch (AmazonClientException ace) { + logger.error("Caught an AmazonClientException "); + logger.error("Error Message: " + ace.getMessage()); + return false; + } + } + + private boolean fileExists(final File file) { + if (file.exists()) { + return true; + } else { + return FileUtils.waitFor(file, 2); + } + } + + public URI getS3Uri(final String fileToUpload) { + if (s3client == null) { + s3client = getS3client(); + } + StringBuffer bucket = new StringBuffer(); + bucket.append(bucketName); + if (folder != null && !folder.isEmpty()) + bucket.append("/").append(folder); + URI fileUri = URI.create(fileToUpload); + File file = new File(fileUri); + URI recordingS3Uri = null; + try { + recordingS3Uri = s3client.getUrl(bucketName, file.getName()).toURI(); + } catch (URISyntaxException e) { + logger.error("Problem during creation of S3 URI"); + } + if (logger.isInfoEnabled()) { + logger.info("Created S3Uri for file: " + fileUri.toString()); + } + return recordingS3Uri; + } + + public URI getPublicUrl (String fileName) throws URISyntaxException { + if (s3client == null) { + s3client = getS3client(); + } + Date date = new Date(); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.MINUTE, minutesToRetainPublicUrl); + if (logger.isInfoEnabled()) { + final String msg = String.format("Prepared amazon s3 public url valid for %s minutes for recording: %s",minutesToRetainPublicUrl, fileName); + logger.info(msg); + } + date = cal.getTime(); + String bucket = bucketName; + if (folder != null && !folder.isEmpty()) { + bucket = bucket.concat("/").concat(folder); + } + GeneratePresignedUrlRequest generatePresignedUrlRequestGET = + new GeneratePresignedUrlRequest(bucket, fileName); + generatePresignedUrlRequestGET.setMethod(HttpMethod.GET); + generatePresignedUrlRequestGET.setExpiration(date); + + return s3client.generatePresignedUrl(generatePresignedUrlRequestGET).toURI(); + } + + private void removeLocalFile(final File file) { + if (!file.delete()) { + if(logger.isInfoEnabled()){ + logger.info("Error while trying to delete the file: "+file.toString()); + } + } + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/BrokenTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/BrokenTests.java new file mode 100644 index 0000000000..debf5db1db --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/BrokenTests.java @@ -0,0 +1,31 @@ +/* + * 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.annotations; + +/** + * Test fails consistently. + * Test should be investigated and fixed as unplanned in current Sprint, + * to allow potential Releases to be deployed. + * @author Jaime + * @author mariafarooq + */ +public interface BrokenTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/Experimental.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/Experimental.java similarity index 94% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/Experimental.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/Experimental.java index 7d17aedd3d..a295885938 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/Experimental.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/Experimental.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.annotations; +package org.restcomm.connect.commons.annotations; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureAltTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureAltTests.java new file mode 100644 index 0000000000..2a4a576f1f --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureAltTests.java @@ -0,0 +1,34 @@ +/* + * 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.annotations; + + +/** + * Result positive: An Alternate Flow is a step or a sequence of + * steps that achieves the use case’s goal following different + * steps than described in the main success scenario. + * But the goal is achieved finally. + * @author Jaime + * @author mariafarooq + * + */ +public interface FeatureAltTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureExpTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureExpTests.java new file mode 100644 index 0000000000..1ce6556c95 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/FeatureExpTests.java @@ -0,0 +1,30 @@ +/* + * 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.annotations; + +/** + * Result negative: An Exception is anything that leads to NOT achieving the use case’s goal. + * @author Jaime + * @author mariafarooq + * + */ +public interface FeatureExpTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/NewTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/NewTests.java new file mode 100644 index 0000000000..0aa43747f4 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/NewTests.java @@ -0,0 +1,24 @@ +/* + * 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.annotations; + +public interface NewTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelClassTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelClassTests.java new file mode 100644 index 0000000000..88df90af4b --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelClassTests.java @@ -0,0 +1,25 @@ +/* + * 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.annotations; + + +public @interface ParallelClassTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelMethodTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelMethodTests.java new file mode 100644 index 0000000000..61705ac732 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelMethodTests.java @@ -0,0 +1,25 @@ +/* + * 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.annotations; + + +public interface ParallelMethodTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelTests.java new file mode 100644 index 0000000000..910b67b70b --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/ParallelTests.java @@ -0,0 +1,24 @@ +/* + * 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.annotations; + +public interface ParallelTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/SequentialClassTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/SequentialClassTests.java new file mode 100644 index 0000000000..9edac85bc9 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/SequentialClassTests.java @@ -0,0 +1,25 @@ +/* + * 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.annotations; + + +public interface SequentialClassTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/UnstableTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/UnstableTests.java new file mode 100644 index 0000000000..fac4e89634 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/UnstableTests.java @@ -0,0 +1,34 @@ +/* + * 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.annotations; + +/** + * Test fails and success with same code in consecutive testsuite runs. + * When a test is detected to be unstable in Ci environment, + * it should be run locally and marked as broken if fails consistently. + * Unstable tests are tech debt and they need to be + * investigated after proper Product Backlog prioritization. + * @author Jaime + * @author mariafarooq + * + */ +public interface UnstableTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMillisTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMillisTests.java new file mode 100644 index 0000000000..7be3ce6dd2 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMillisTests.java @@ -0,0 +1,24 @@ +/* + * 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.annotations; + +public interface WithInMillisTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMinsTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMinsTests.java new file mode 100644 index 0000000000..4a14c0d352 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInMinsTests.java @@ -0,0 +1,24 @@ +/* + * 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.annotations; + +public interface WithInMinsTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInSecsTests.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInSecsTests.java new file mode 100644 index 0000000000..eb1c480931 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/WithInSecsTests.java @@ -0,0 +1,24 @@ +/* + * 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.annotations; + +public interface WithInSecsTests { + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/Immutable.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/Immutable.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/Immutable.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/Immutable.java index 4530d9724d..f6c9517d67 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/Immutable.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/Immutable.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.annotations.concurrency; +package org.restcomm.connect.commons.annotations.concurrency; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/NotThreadSafe.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/NotThreadSafe.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/NotThreadSafe.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/NotThreadSafe.java index 37fedc4590..1fd9b1ce76 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/NotThreadSafe.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/NotThreadSafe.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.annotations.concurrency; +package org.restcomm.connect.commons.annotations.concurrency; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/ThreadSafe.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/ThreadSafe.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/ThreadSafe.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/ThreadSafe.java index 3ebb3bd708..496061894c 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/annotations/concurrency/ThreadSafe.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/annotations/concurrency/ThreadSafe.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.annotations.concurrency; +package org.restcomm.connect.commons.annotations.concurrency; /** * @author quintana.thomas@gmail.com (Thomas Quintana) 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 new file mode 100644 index 0000000000..0f14692278 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCache.java @@ -0,0 +1,193 @@ +/* + * 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.cache; + +import akka.actor.ActorRef; +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; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public final class DiskCache extends RestcommUntypedActor { + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + private final String cacheDir; + private final String cacheUri; + + // flag for cache disabling in *.wav files usage case + private boolean wavNoCache = false; + private FileDownloader downloader; + + public DiskCache(FileDownloader downloader, String cacheDir, String cacheUri, final boolean create, final boolean wavNoCache) { + super(); + + this.wavNoCache = wavNoCache; + this.downloader = downloader; + + // Format the cache path. + if (!cacheDir.endsWith("/")) { + cacheDir += "/"; + } + // Create the cache path if specified. + final File path = new File(cacheDir); + // if (create) { + // path.mkdirs(); + // } + + // Make sure the cache path exists and is a directory. + if (!path.exists() || !path.isDirectory()) { + // throw new IllegalArgumentException(cacheDir + " is not a valid cache cacheDir."); + path.mkdirs(); + } + // Format the cache URI. + this.cacheDir = cacheDir; + if (!cacheUri.endsWith("/")) { + cacheUri += "/"; + } + this.cacheUri = cacheUri; + } + + public DiskCache(FileDownloader downloader, final String cacheDir, final String cacheUri, final boolean create) { + this(downloader, cacheDir, cacheUri, create, false); + } + + public DiskCache(FileDownloader downloader, final String cacheDir, final String cacheUri) { + this(downloader, cacheDir, cacheUri, false); + } + + // constructor for compatibility with existing tests + public DiskCache(final String cacheDir, final String cacheUri, final boolean create) { + this(new FileDownloader(), cacheDir, cacheUri, create, false); + } + + public URI cache(final DiskCacheRequest request) throws IOException, URISyntaxException { + if (StringUtils.isNotEmpty(request.hash())) { + return handleHashedRequest(request); + } else if ("file".equalsIgnoreCase(request.uri().getScheme())) { + return handleLocalFile(request); + } else { + return handleExternalUrl(request); + } + } + + private URI handleHashedRequest(final DiskCacheRequest request) throws FileNotFoundException { + // This is a check cache request + final String extension = "wav"; + final String hash = request.hash(); + final String filename = hash + "." + extension; + Path p = Paths.get(cacheDir + filename); + + if (Files.exists(p)) { + // return URI.create(matchedFile.getAbsolutePath()); + return URI.create(this.cacheUri + filename); + } else { + throw new FileNotFoundException("File "+filename+" NotFound"); + } + } + + private URI handleLocalFile(final DiskCacheRequest request) throws IOException { + File origFile = new File(request.uri()); + File destFile = new File(cacheDir + origFile.getName()); + if (!destFile.exists()) { + FileUtils.moveFile(origFile, destFile); + } + return URI.create(this.cacheUri + destFile.getName()); + } + + private URI handleExternalUrl(final DiskCacheRequest request) throws IOException, URISyntaxException { + //Handle all the rest + // This is a request to cache a URI + String hash; + URI uri; + URI requestUri = request.uri(); + String requestUriText = requestUri.toString(); + if (wavNoCache && "wav".equalsIgnoreCase(extension(requestUri))) { + return requestUri; + }else if (requestUriText.contains("hash")) { + String fragment = requestUri.getFragment(); + hash = fragment.replace("hash=", ""); + String uriStr = requestUriText.replace(fragment, "").replace("#", ""); + uri = URI.create(uriStr); + } else { + uri = requestUri; + hash = new Sha256Hash(requestUriText).toHex(); + } + + final String extension = extension(uri).toLowerCase(); + File path = null; + if (!extension.equalsIgnoreCase("wav")) { + path = new File(cacheDir + hash + "." + extension); + if (!path.exists()) { + downloader.download(uri, path); + } + return URI.create(this.cacheUri + hash + "." + extension); + } else { + path = new File(cacheDir + hash + ".wav" ); + if (!path.exists()) { + downloader.download(uri, path); + } + return URI.create(this.cacheUri + hash + ".wav"); + } + } + + @Override + public void onReceive(final Object message) throws Exception { + if (!(message instanceof DiskCacheRequest)) { + logger.warning("Unexpected request type"); + return; + } + final Class klass = message.getClass(); + final ActorRef self = self(); + final ActorRef sender = sender(); + if (DiskCacheRequest.class.equals(klass)) { + DiskCacheResponse response; + try { + response = new DiskCacheResponse(cache((DiskCacheRequest) message)); + } catch (final Exception exception) { + if (logger.isDebugEnabled()) { + logger.debug("Issue while caching", exception); + } + response = new DiskCacheResponse(exception); + } + sender.tell(response, self); + } + } + + private static String extension(final URI uri) { + final String path = uri.getPath(); + return path.substring(path.lastIndexOf(".") + 1); + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheFactory.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheFactory.java new file mode 100644 index 0000000000..bf6983c688 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheFactory.java @@ -0,0 +1,30 @@ +package org.restcomm.connect.commons.cache; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.configuration.sets.CacheConfigurationSet; + +public final class DiskCacheFactory { + + private final CacheConfigurationSet cfg; + + private final FileDownloader downloader; + + public DiskCacheFactory(Configuration cfg) { + this(new RestcommConfiguration(cfg)); + } + + public DiskCacheFactory(RestcommConfiguration cfg) { + this.cfg = cfg.getCache(); + this.downloader = new FileDownloader(); + } + + public DiskCache getDiskCache() { + return new DiskCache(downloader, this.cfg.getCachePath(), this.cfg.getCacheUri(), false, cfg.isNoWavCache()); + } + + // constructor for compatibility with existing cache implementation + public DiskCache getDiskCache(final String cachePath, final String cacheUri) { + return new DiskCache(downloader, cachePath, cacheUri, true, cfg.isNoWavCache()); + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheRequest.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheRequest.java similarity index 91% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheRequest.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheRequest.java index 603da41c4c..b9d3764894 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/DiskCacheRequest.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheRequest.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.cache; +package org.restcomm.connect.commons.cache; import java.net.URI; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheResponse.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheResponse.java new file mode 100644 index 0000000000..8071171b2b --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCacheResponse.java @@ -0,0 +1,51 @@ +/* + * 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.cache; + +import java.net.URI; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.patterns.StandardResponse; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public final class DiskCacheResponse extends StandardResponse { + public DiskCacheResponse(final Throwable cause, final String message) { + super(cause, message); + } + + public DiskCacheResponse(final Throwable cause) { + super(cause); + } + + public DiskCacheResponse(final URI object) { + super(object); + } + + @Override + public String toString() { + if(cause() == null){ + return "DiskCacheResponse [" + super.toString() + "]"; + } + return (new StringBuffer("DiskCacheResponse [succeeded=").append(succeeded()).append(", cause=").append(cause().getMessage()).append(", message=").append(error()).append(", object=").append(get()).append("]")).toString(); + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/FileDownloader.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/FileDownloader.java new file mode 100644 index 0000000000..293695e07a --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/FileDownloader.java @@ -0,0 +1,82 @@ +package org.restcomm.connect.commons.cache; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.net.URI; +import java.net.URISyntaxException; + +/** + * @author Gennadiy Dubina + */ +public class FileDownloader { + +public URI download(URI requestUri, File pathToSave) throws IOException, URISyntaxException { + final File tmp = new File(pathToSave + "." + "tmp"); + InputStream input = null; + OutputStream output = null; + HttpClient client = null; + HttpResponse httpResponse = null; + try { + if (requestUri.getScheme().equalsIgnoreCase("https")) { + //Handle the HTTPS URIs + client = CustomHttpClientBuilder.buildDefaultClient(RestcommConfiguration.getInstance().getMain()); + /*URI result = new URIBuilder() + .setScheme(requestUri.getScheme()) + .setHost(requestUri.getHost()) + .setPort(requestUri.getPort()) + .setPath(requestUri.getPath()) + .build(); + HttpGet httpRequest = new HttpGet(result); + */ + HttpGet httpRequest = new HttpGet(requestUri); + httpResponse = client.execute(httpRequest); + int code = httpResponse.getStatusLine().getStatusCode(); + + if (code >= 400) { + String requestUrl = httpRequest.getRequestLine().getUri(); + String errorReason = httpResponse.getStatusLine().getReasonPhrase(); + String httpErrorMessage = String.format( + "Error while fetching http resource: %s \n Http error code: %d \n Http error message: %s", + requestUrl, code, errorReason); + throw new IOException(httpErrorMessage); + } + input = httpResponse.getEntity().getContent(); + } else { + input = requestUri.toURL().openStream(); + } + output = new FileOutputStream(tmp); + final byte[] buffer = new byte[4096]; + int read = 0; + do { + read = input.read(buffer, 0, 4096); + if (read > 0) { + output.write(buffer, 0, read); + } + } while (read != -1); + tmp.renameTo(pathToSave); + } finally { + if (input != null) { + input.close(); + } + if (output != null) { + output.close(); + } + if (httpResponse != null) { + ((CloseableHttpResponse) httpResponse).close(); + httpResponse = null; + } + } + + return pathToSave.toURI(); + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/HashGenerator.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/HashGenerator.java similarity index 86% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/HashGenerator.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/HashGenerator.java index 7d5fb7540b..b6b9508aab 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/cache/HashGenerator.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/HashGenerator.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.cache; +package org.restcomm.connect.commons.cache; import org.apache.shiro.crypto.hash.Sha256Hash; diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/CustomHttpClientBuilder.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/CustomHttpClientBuilder.java new file mode 100644 index 0000000000..2e604e7374 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/CustomHttpClientBuilder.java @@ -0,0 +1,294 @@ +/* + * 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.common.http; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.utils.HttpClientUtils; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.util.PublicSuffixMatcher; +import org.apache.http.conn.util.PublicSuffixMatcherLoader; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; +import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; +import org.apache.http.nio.conn.NoopIOSessionStrategy; +import org.apache.http.nio.conn.SchemeIOSessionStrategy; +import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; +import org.apache.http.nio.reactor.IOReactorException; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; + +/** + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +public class CustomHttpClientBuilder { + + private CustomHttpClientBuilder() { + } + + private static CloseableHttpClient defaultClient = null; + private static CloseableHttpAsyncClient closeableHttpAsyncClient = null; + + public static synchronized void stopDefaultClient() { + if (defaultClient != null) { + HttpClientUtils.closeQuietly(defaultClient); + defaultClient = null; + } + if (closeableHttpAsyncClient != null) { + try { + if(closeableHttpAsyncClient.isRunning()) + closeableHttpAsyncClient.close(); + } catch (IOException e) { + } + closeableHttpAsyncClient = null; + } + } + + public static synchronized CloseableHttpClient buildDefaultClient(MainConfigurationSet config) { + if (defaultClient == null) { + defaultClient = build(config); + } + return defaultClient; + } + + public static synchronized CloseableHttpAsyncClient buildCloseableHttpAsyncClient(MainConfigurationSet config) { + if (closeableHttpAsyncClient == null) { + closeableHttpAsyncClient = buildAsync(config); + closeableHttpAsyncClient.start(); + } + return closeableHttpAsyncClient; + } + + public static CloseableHttpClient build(MainConfigurationSet config) { + int timeoutConnection = config.getResponseTimeout(); + return build(config, timeoutConnection); + } + + private static CloseableHttpAsyncClient buildAsync(MainConfigurationSet config) { + int timeoutConnection = config.getResponseTimeout(); + return buildAsync(config, timeoutConnection); + } + + private static CloseableHttpAsyncClient buildAsync(MainConfigurationSet config, int timeout) { + HttpAsyncClientBuilder builder = HttpAsyncClients.custom(); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(timeout) + .setConnectionRequestTimeout(config.getDefaultHttpConnectionRequestTimeout()) + .setSocketTimeout(timeout) + .setCookieSpec(CookieSpecs.STANDARD).build(); + builder.setDefaultRequestConfig(requestConfig); + + SslMode mode = config.getSslMode(); + SSLIOSessionStrategy sessionStrategy = null; + + if (mode == SslMode.strict) { + sessionStrategy = buildStrictSSLIOSessionStrategy(); + } else { + sessionStrategy = buildAllowallSSLIOSessionStrategy(); + } + builder.setSSLStrategy(sessionStrategy); + + builder.setMaxConnPerRoute(config.getDefaultHttpMaxConnsPerRoute()); + builder.setMaxConnTotal(config.getDefaultHttpMaxConns()); + //builder.setConnectionTimeToLive(config.getDefaultHttpTTL(), TimeUnit.MILLISECONDS); + if (config.getDefaultHttpRoutes() != null + && config.getDefaultHttpRoutes().size() > 0) { + Registry reg = RegistryBuilder.create() + .register("http", NoopIOSessionStrategy.INSTANCE) + .register("https", sessionStrategy) + .build(); + try { + final PoolingNHttpClientConnectionManager poolingmgr = new PoolingNHttpClientConnectionManager( + new DefaultConnectingIOReactor(), + null, + reg, + null, + null, + config.getDefaultHttpTTL(), + TimeUnit.MILLISECONDS); + //ensure conn configuration is set again for new conn manager + poolingmgr.setMaxTotal(config.getDefaultHttpMaxConns()); + poolingmgr.setDefaultMaxPerRoute(config.getDefaultHttpMaxConnsPerRoute()); + for (InetSocketAddress addr : config.getDefaultHttpRoutes().keySet()) { + HttpRoute r = new HttpRoute(new HttpHost(addr.getHostName(), addr.getPort())); + poolingmgr.setMaxPerRoute(r, config.getDefaultHttpRoutes().get(addr)); + } + builder.setConnectionManager(poolingmgr); + } catch (IOReactorException e) { + throw new RuntimeException("Error creating CloseableHttpAsyncClient", e); + } + } + return builder.build(); + } + + private static CloseableHttpClient build(MainConfigurationSet config, int timeout) { + HttpClientBuilder builder = HttpClients.custom(); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(timeout) + .setConnectionRequestTimeout(config.getDefaultHttpConnectionRequestTimeout()) + .setSocketTimeout(timeout) + .setCookieSpec(CookieSpecs.STANDARD).build(); + builder.setDefaultRequestConfig(requestConfig); + + SslMode mode = config.getSslMode(); + SSLConnectionSocketFactory sslsf = null; + if (mode == SslMode.strict) { + sslsf = buildStrictFactory(); + } else { + sslsf = buildAllowallFactory(); + } + builder.setSSLSocketFactory(sslsf); + + builder.setMaxConnPerRoute(config.getDefaultHttpMaxConnsPerRoute()); + builder.setMaxConnTotal(config.getDefaultHttpMaxConns()); + builder.setConnectionTimeToLive(config.getDefaultHttpTTL(), TimeUnit.MILLISECONDS); + if (config.getDefaultHttpRoutes() != null + && config.getDefaultHttpRoutes().size() > 0) { + if (sslsf == null) { + //strict mode with no system https properties + //taken from apache buider code + PublicSuffixMatcher publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault(); + DefaultHostnameVerifier hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy); + sslsf = new SSLConnectionSocketFactory( + SSLContexts.createDefault(), + hostnameVerifierCopy); + } + Registry reg = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslsf) + .build(); + final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( + reg, + null, + null, + null, + config.getDefaultHttpTTL(), + TimeUnit.MILLISECONDS); + //ensure conn configuration is set again for new conn manager + poolingmgr.setMaxTotal(config.getDefaultHttpMaxConns()); + poolingmgr.setDefaultMaxPerRoute(config.getDefaultHttpMaxConnsPerRoute()); + for (InetSocketAddress addr : config.getDefaultHttpRoutes().keySet()) { + HttpRoute r = new HttpRoute(new HttpHost(addr.getHostName(), addr.getPort())); + poolingmgr.setMaxPerRoute(r, config.getDefaultHttpRoutes().get(addr)); + } + builder.setConnectionManager(poolingmgr); + } + return builder.build(); + } + + private static String[] getSSLPrototocolsFromSystemProperties() { + String protocols = System.getProperty("jdk.tls.client.protocols"); + if (protocols == null) { + protocols = System.getProperty("https.protocols"); + } + + if (protocols != null) { + String[] protocolsArray = protocols.split(","); + return protocolsArray; + } + return null; + } + + private static SSLConnectionSocketFactory buildStrictFactory() { + try { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + SSLContextBuilder.create().build(), + getSSLPrototocolsFromSystemProperties(), + null, + // new String[]{"TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA"}, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + return sslsf; + } catch (KeyManagementException | NoSuchAlgorithmException e) { + throw new RuntimeException("Error creating HttpClient", e); + } + } + + private static SSLConnectionSocketFactory buildAllowallFactory() { + try { + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + builder.build(), + getSSLPrototocolsFromSystemProperties(), + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + return sslsf; + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + throw new RuntimeException("Error creating HttpClient", e); + } + } + + private static SSLIOSessionStrategy buildStrictSSLIOSessionStrategy(){ + try { + SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy( + SSLContextBuilder.create().build(), + getSSLPrototocolsFromSystemProperties(), + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + return sessionStrategy; + } catch (KeyManagementException | NoSuchAlgorithmException e) { + throw new RuntimeException("Error creating HttpAsycClient", e); + } + } + + private static SSLIOSessionStrategy buildAllowallSSLIOSessionStrategy(){ + try { + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + + SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy( + builder.build(), + getSSLPrototocolsFromSystemProperties(), + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + return sessionStrategy; + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + throw new RuntimeException("Error creating HttpAsycClient", e); + } + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/SslMode.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/SslMode.java new file mode 100644 index 0000000000..fe178edd63 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/common/http/SslMode.java @@ -0,0 +1,5 @@ +package org.restcomm.connect.commons.common.http; + +public enum SslMode { + strict, allowall; +} 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 new file mode 100644 index 0000000000..a5746eb4f1 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/RestcommConfiguration.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.commons.configuration; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +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.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; + +/** + * Singleton like class that provides access to ConfigurationSets. + * Use get+() functions to access configuration sets. + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +public class RestcommConfiguration { + + private final Map sets = new ConcurrentHashMap(); + + public RestcommConfiguration() { + // No ConfigurationSets added. You'll have to it manually with addConfigurationSet(). + } + + public RestcommConfiguration(Configuration apacheConf) { + // addConfigurationSet("main", new MainConfigurationSet( new ApacheConfigurationSource(apacheConf))); + ApacheConfigurationSource apacheCfgSrc = new ApacheConfigurationSource(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))); + // ... + } + + public void addConfigurationSet(String setKey, ConfigurationSet set ) { + sets.put(setKey, set); + } + public T get(String key, Class type) { + return type.cast(sets.get(key)); + } + + public MainConfigurationSet getMain() { + return (MainConfigurationSet) sets.get("main"); + } + /* + public void reloadMain() { + MainConfigurationSet oldMain = getMain(); + MainConfigurationSet newMain = new MainConfigurationSet(oldMain.getSource()); + sets.put("main", newMain); + } + */ + + // define getters for additional ConfigurationSets here + // ... + public CacheConfigurationSet getCache() { + return (CacheConfigurationSet) sets.get("cache"); + } + + 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) { + synchronized (RestcommConfiguration.class) { + if (instance == null) { + instance = new RestcommConfiguration(apacheConf); + } + } + return instance; + } + public static RestcommConfiguration getInstance() { + if (instance == null) + throw new IllegalStateException("RestcommConfiguration has not been initialized."); + return instance; + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/CacheConfigurationSet.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/CacheConfigurationSet.java new file mode 100644 index 0000000000..e16d326cef --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/CacheConfigurationSet.java @@ -0,0 +1,33 @@ +/* + * 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; + +/** + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public interface CacheConfigurationSet { + + boolean isNoWavCache(); + + String getCachePath(); + + String getCacheUri(); +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/MainConfigurationSet.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/MainConfigurationSet.java new file mode 100644 index 0000000000..260d29de3a --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/MainConfigurationSet.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; + +import java.net.InetSocketAddress; +import java.util.Map; +import org.restcomm.connect.commons.common.http.SslMode; + +/** + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public interface MainConfigurationSet { + SslMode getSslMode(); + + int getResponseTimeout(); + + Integer getDefaultHttpConnectionRequestTimeout(); + + Integer getDefaultHttpMaxConns(); + + Integer getDefaultHttpMaxConnsPerRoute(); + + Integer getDefaultHttpTTL(); + + Map getDefaultHttpRoutes(); + + boolean isUseHostnameToResolveRelativeUrls(); + + String getHostname(); + + boolean getBypassLbForClients(); + + void setInstanceId(String instanceId); + + String getInstanceId(); + + String getApiVersion(); + + int getRecordingMaxDelay (); + + long getConferenceTimeout(); + + void setConferenceTimeout(long conferenceTimeout); +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/RcmlserverConfigurationSet.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/RcmlserverConfigurationSet.java new file mode 100644 index 0000000000..24ea459f52 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/RcmlserverConfigurationSet.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public interface RcmlserverConfigurationSet { + String getApiPath(); + String getBaseUrl(); + Boolean getNotify(); + Integer getTimeout(); // how much to wait for response to a notification request before giving up + Integer getTimeoutPerNotification(); // now much more to increase timeout for each notification that is sent +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/CacheConfigurationSetImpl.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/CacheConfigurationSetImpl.java new file mode 100644 index 0000000000..8fb7922f46 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/CacheConfigurationSetImpl.java @@ -0,0 +1,81 @@ +/* + * 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.restcomm.connect.commons.configuration.sets.CacheConfigurationSet; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +public class CacheConfigurationSetImpl extends ConfigurationSet implements CacheConfigurationSet { + public static final String CACHE_NO_WAV_KEY = "runtime-settings.cache-no-wav"; + public static final String CACHE_PATH_KEY = "runtime-settings.cache-path"; + public static final String CACHE_URI_KEY = "runtime-settings.cache-uri"; + + private boolean noWavCache; + private String cachePath; + private String cacheUri; + + public CacheConfigurationSetImpl (ConfigurationSource source) { + super(source); + + String value = source.getProperty(CACHE_NO_WAV_KEY); + + // default flag value is "false" if appropriate key "cache-no-wav" is absent in configuration *.xml file + noWavCache = (value == null) ? false : Boolean.valueOf(source.getProperty(CACHE_NO_WAV_KEY)); + + cachePath = source.getProperty(CACHE_PATH_KEY); + + cacheUri = source.getProperty(CACHE_URI_KEY); + } + + public CacheConfigurationSetImpl(boolean noWavCache, String cachePath, String cacheUri) { + super(null); + this.noWavCache = noWavCache; + this.cachePath = cachePath; + this.cacheUri = cacheUri; + } + + @Override + public boolean isNoWavCache() { + return noWavCache; + } + + @Override + public String getCachePath() { + return cachePath; + } + + @Override + public String getCacheUri() { + return cacheUri; + } + + public void setNoWavCache(boolean noWavCache) { + this.noWavCache = noWavCache; + } + + public void setCachePath(String cachePath) { + this.cachePath = cachePath; + } + + public void setCacheUri(String cacheUri) { + this.cacheUri = cacheUri; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/ConfigurationSet.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/ConfigurationSet.java new file mode 100644 index 0000000000..2dbad0bdce --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/ConfigurationSet.java @@ -0,0 +1,43 @@ +/* + * 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.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +/** + * A logical group of configuration options. It encapsulates storage, initialization + * and validation operations. Extend it to add new groups. + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +public class ConfigurationSet { + private final ConfigurationSource source; + + protected ConfigurationSet(ConfigurationSource source) { + super(); + this.source = source; + } + + public ConfigurationSource getSource() { + return source; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MainConfigurationSetImpl.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MainConfigurationSetImpl.java new file mode 100644 index 0000000000..90562ea277 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MainConfigurationSetImpl.java @@ -0,0 +1,274 @@ +/* + * 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 java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.common.http.SslMode; +import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +/** + * Provides a typed interface to a set of configuration options retrieved from a + * configuration source. + * + * To add a new option in this set define its name as static fields and then + * initialize, validate it in the constructor. + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +@Immutable +public class MainConfigurationSetImpl extends ConfigurationSet implements MainConfigurationSet { + + private static final String SSL_MODE_KEY = "http-client.ssl-mode"; + private static final String HTTP_RESPONSE_TIMEOUT = "http-client.response-timeout"; + private static final String HTTP_CONNECTION_REQUEST_TIMEOUT = "http-client.connection-request-timeout"; + private static final String HTTP_MAX_CONN_TOTAL = "http-client.max-conn-total"; + private static final String HTTP_MAX_CONN_PER_ROUTE = "http-client.max-conn-per-route"; + private static final String HTTP_CONNECTION_TIME_TO_LIVE = "http-client.connection-time-to-live"; + private static final String HTTP_ROUTES_HOST = "http-client.routes-host"; + private static final String HTTP_ROUTES_PORT = "http-client.routes-port"; + private static final String HTTP_ROUTES_CONN = "http-client.routes-conn"; + private static final String CONFERENCE_TIMEOUT_KEY = "runtime-settings.conference-timeout"; + private static final long CONFERENCE_TIMEOUT_DEFAULT = 14400; //4 hours in seconds + private static final SslMode SSL_MODE_DEFAULT = SslMode.strict; + private SslMode sslMode; + private int responseTimeout; + private Integer connectionRequestTimeout; + private Integer defaultHttpMaxConns; + private Integer defaultHttpMaxConnsPerRoute; + private Integer defaultHttpTTL; + private Map defaultHttpRoutes = new HashMap(); + private static final String USE_HOSTNAME_TO_RESOLVE_RELATIVE_URL_KEY = "http-client.use-hostname-to-resolve-relative-url"; + private static final String HOSTNAME_TO_USE_FOR_RELATIVE_URLS_KEY = "http-client.hostname"; + private static final boolean RESOLVE_RELATIVE_URL_WITH_HOSTNAME_DEFAULT = true; + private boolean useHostnameToResolveRelativeUrls; + private String hostname; + private String instanceId; + private String apiVersion; + private int recordingMaxDelay; + private long conferenceTimeout; + + public static final String BYPASS_LB_FOR_CLIENTS = "bypass-lb-for-clients"; + private boolean bypassLbForClients = false; + + public MainConfigurationSetImpl(ConfigurationSource source) { + super(source); + SslMode sslMode; + boolean resolveRelativeUrlWithHostname; + String resolveRelativeUrlHostname; + boolean bypassLb = false; + + try { + responseTimeout = Integer.parseInt(source.getProperty(HTTP_RESPONSE_TIMEOUT, "5000")); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + HTTP_RESPONSE_TIMEOUT + "' configuration setting", e); + } + try { + connectionRequestTimeout = Integer.parseInt(source.getProperty(HTTP_CONNECTION_REQUEST_TIMEOUT,String.valueOf(responseTimeout))); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + HTTP_RESPONSE_TIMEOUT + "' configuration setting", e); + } + try { + defaultHttpMaxConns = Integer.parseInt(source.getProperty(HTTP_MAX_CONN_TOTAL, "2000")); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + HTTP_MAX_CONN_TOTAL + "' configuration setting", e); + } + try { + defaultHttpMaxConnsPerRoute = Integer.parseInt(source.getProperty(HTTP_MAX_CONN_PER_ROUTE, "100")); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + HTTP_MAX_CONN_PER_ROUTE + "' configuration setting", e); + } + try { + defaultHttpTTL = Integer.parseInt(source.getProperty(HTTP_CONNECTION_TIME_TO_LIVE, "30000")); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + HTTP_CONNECTION_TIME_TO_LIVE + "' configuration setting", e); + } + + try { + String delimiter = ","; + String routesHostProp = source.getProperty(HTTP_ROUTES_HOST, ""); + if (!routesHostProp.isEmpty()) { + String[] routesHostList = routesHostProp.split(delimiter); + String routesPortProp = source.getProperty(HTTP_ROUTES_PORT, ""); + String[] routesPortList = routesPortProp.split(delimiter); + String routesConnProp = source.getProperty(HTTP_ROUTES_CONN, ""); + String[] routesConnList = routesConnProp.split(delimiter); + for (int i = 0; i < routesHostList.length; i++) { + Integer port = Integer.valueOf(routesPortList[i]); + Integer conn = Integer.valueOf(routesConnList[i]); + InetSocketAddress addr = new InetSocketAddress(routesHostList[i], port); + defaultHttpRoutes.put(addr, conn); + } + } + + } catch (Throwable e) {//to catch array index out of bounds + throw new RuntimeException("Error initializing '" + HTTP_ROUTES_CONN + "' configuration setting", e); + } + + // http-client.ssl-mode + try { + sslMode = SSL_MODE_DEFAULT; + String sslModeRaw = source.getProperty(SSL_MODE_KEY); + if (!StringUtils.isEmpty(sslModeRaw)) { + sslMode = SslMode.valueOf(sslModeRaw); + } + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + SSL_MODE_KEY + "' configuration setting", e); + } + this.sslMode = sslMode; + + // http-client.hostname + // http-client.use-hostname-to-resolve-relative-url + try { + resolveRelativeUrlWithHostname = RESOLVE_RELATIVE_URL_WITH_HOSTNAME_DEFAULT; + resolveRelativeUrlWithHostname = Boolean.valueOf(source.getProperty(USE_HOSTNAME_TO_RESOLVE_RELATIVE_URL_KEY)); + resolveRelativeUrlHostname = source.getProperty("http-client.hostname"); + bypassLb = Boolean.valueOf(source.getProperty(BYPASS_LB_FOR_CLIENTS)); + } catch (Exception e) { + throw new RuntimeException("Error initializing '" + USE_HOSTNAME_TO_RESOLVE_RELATIVE_URL_KEY + "' configuration setting", e); + } + this.useHostnameToResolveRelativeUrls = resolveRelativeUrlWithHostname; + this.hostname = resolveRelativeUrlHostname; + bypassLbForClients = bypassLb; + apiVersion = source.getProperty("runtime-settings.api-version"); + + this.recordingMaxDelay = Integer.parseInt(source.getProperty("runtime-setting.recording-max-delay", "2000")); + try{ + this.conferenceTimeout = Long.parseLong(source.getProperty(CONFERENCE_TIMEOUT_KEY, ""+CONFERENCE_TIMEOUT_DEFAULT)); + }catch(NumberFormatException nfe){ + this.conferenceTimeout = CONFERENCE_TIMEOUT_DEFAULT; + } + } + + public MainConfigurationSetImpl(SslMode sslMode, int responseTimeout, boolean useHostnameToResolveRelativeUrls, String hostname, String instanceId, boolean bypassLbForClients) { + super(null); + this.sslMode = sslMode; + this.responseTimeout = responseTimeout; + this.useHostnameToResolveRelativeUrls = useHostnameToResolveRelativeUrls; + this.hostname = hostname; + this.instanceId = instanceId; + this.bypassLbForClients = bypassLbForClients; + } + + @Override + public SslMode getSslMode() { + return sslMode; + } + + @Override + public int getResponseTimeout() { + return responseTimeout; + } + + @Override + public boolean isUseHostnameToResolveRelativeUrls() { + return useHostnameToResolveRelativeUrls; + } + + @Override + public String getHostname() { + return hostname; + } + + @Override + public boolean getBypassLbForClients() { + return bypassLbForClients; + } + + @Override + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + @Override + public String getInstanceId() { + return this.instanceId; + } + + public void setSslMode(SslMode sslMode) { + this.sslMode = sslMode; + } + + public void setResponseTimeout(int responseTimeout) { + this.responseTimeout = responseTimeout; + } + + public void setUseHostnameToResolveRelativeUrls(boolean useHostnameToResolveRelativeUrls) { + this.useHostnameToResolveRelativeUrls = useHostnameToResolveRelativeUrls; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void setBypassLbForClients(boolean bypassLbForClients) { + this.bypassLbForClients = bypassLbForClients; + } + + public String getApiVersion() { + return apiVersion; + } + + @Override + public int getRecordingMaxDelay() { + return recordingMaxDelay; + } + + @Override + public Integer getDefaultHttpMaxConns() { + return defaultHttpMaxConns; + } + + @Override + public Integer getDefaultHttpMaxConnsPerRoute() { + return defaultHttpMaxConnsPerRoute; + } + + @Override + public Integer getDefaultHttpTTL() { + return defaultHttpTTL; + } + + @Override + public Map getDefaultHttpRoutes() { + return defaultHttpRoutes; + } + + @Override + public Integer getDefaultHttpConnectionRequestTimeout() { + return connectionRequestTimeout; + } + + @Override + public long getConferenceTimeout() { + return conferenceTimeout; + } + + @Override + public void setConferenceTimeout(long conferenceTimeout) { + this.conferenceTimeout = conferenceTimeout; + } +} 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..8f7b50fea2 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MgAsrConfigurationSet.java @@ -0,0 +1,74 @@ +/* + * 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; + private final int asrMRT; + private final int defaultGatheringTimeout; + + 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]"); + asrMRT = config.containsKey("runtime-settings.asr-mrt-timeout") ? config.getInt("runtime-settings.asr-mrt-timeout") : 60; + defaultGatheringTimeout = config.containsKey("runtime-settings.default-gathering-timeout") ? config.getInt("runtime-settings.default-gathering-timeout") : 5; + } + + public List getDrivers() { + return drivers; + } + + public String getDefaultDriver() { + return defaultDriver; + } + + public List getLanguages() { + return languages; + } + + public String getDefaultLanguage() { + return defaultLanguage; + } + + public int getAsrMRT() { + return asrMRT; + } + + public int getDefaultGatheringTimeout() { + return defaultGatheringTimeout; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/RcmlserverConfigurationSetImpl.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/RcmlserverConfigurationSetImpl.java new file mode 100644 index 0000000000..d2e901c2a2 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/RcmlserverConfigurationSetImpl.java @@ -0,0 +1,110 @@ +/* + * 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.lang.StringUtils; +import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RcmlserverConfigurationSetImpl extends ConfigurationSet implements RcmlserverConfigurationSet { + private static final String BASE_URL_KEY = "rcmlserver.base-url"; + private static final String API_PATH_KEY = "rcmlserver.api-path"; + private static final String NOTIFY_KEY = "rcmlserver.notifications"; + private static final String TIMEOUT_KEY = "rcmlserver.timeout"; + private static final String TIMEOUT_PER_NOTIFICATION_KEY = "rcmlserver.timeout-per-notification"; + private String baseUrl = null; + private String apiPath = null; + private Boolean notify = false; + private Integer timeout = 5000; + private Integer timeoutPerNotification = 500; + + public RcmlserverConfigurationSetImpl(ConfigurationSource source) { + super(source); + + String value = source.getProperty(BASE_URL_KEY); + if ( !StringUtils.isEmpty(value) ) { + value = value.trim(); + if (value.endsWith("/")) // remove trailing '/' if present + value = value.substring(0,value.length()-2); + this.baseUrl = value; + } + + value = source.getProperty(API_PATH_KEY); + if ( !StringUtils.isEmpty(value) ) { + value = value.trim(); + if (value.endsWith("/")) // remove trailing '/' if present + value = value.substring(0,value.length()-2); + this.apiPath = value; + } + + value = source.getProperty(NOTIFY_KEY); + try { + this.notify = Boolean.parseBoolean(value); + } catch (Exception e) {} + + value = source.getProperty(TIMEOUT_KEY); + try { + this.timeout = Integer.parseInt(value); + } catch (Exception e) {} + + value = source.getProperty(TIMEOUT_PER_NOTIFICATION_KEY); + try { + this.timeoutPerNotification= Integer.parseInt(value); + } catch (Exception e) {} + } + + public RcmlserverConfigurationSetImpl(ConfigurationSource source, String baseUrl, Boolean notify, Integer timeout, Integer timeoutPerNotification) { + super(source); + this.baseUrl = baseUrl; + this.notify = notify; + this.timeout = timeout; + this.timeoutPerNotification = timeoutPerNotification; + } + + @Override + public String getBaseUrl() { + return baseUrl; + } + + @Override + public String getApiPath() { + return apiPath; + } + + @Override + public Boolean getNotify() { + return notify; + } + + @Override + public Integer getTimeout() { + return this.timeout; + } + + @Override + public Integer getTimeoutPerNotification() { + return this.timeoutPerNotification; + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ApacheConfigurationSource.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ApacheConfigurationSource.java new file mode 100644 index 0000000000..30328397f6 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ApacheConfigurationSource.java @@ -0,0 +1,49 @@ +/* + * 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.sources; + +import org.apache.commons.configuration.Configuration; + +/** + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +public class ApacheConfigurationSource implements ConfigurationSource { + + private final Configuration apacheConfiguration; + + public ApacheConfigurationSource(Configuration apacheConfiguration) { + super(); + this.apacheConfiguration = apacheConfiguration; + } + + @Override + public String getProperty(String key) { + return apacheConfiguration.getString(key); + } + + @Override + public String getProperty (String key, String defValue) { + return apacheConfiguration.getString(key, defValue); + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ConfigurationSource.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ConfigurationSource.java new file mode 100644 index 0000000000..4d19aabc6f --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sources/ConfigurationSource.java @@ -0,0 +1,30 @@ +/* + * 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.sources; + +/** + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + * + */ +public interface ConfigurationSource { + String getProperty(String key); + String getProperty (String key, String defValue); +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/Sid.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/Sid.java new file mode 100644 index 0000000000..6f664d15c5 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/Sid.java @@ -0,0 +1,167 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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; + +import java.util.UUID; +import java.util.regex.Pattern; + +import org.apache.shiro.crypto.hash.Md5Hash; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@Immutable +public final class Sid { + public static final Pattern pattern = Pattern.compile("[a-zA-Z0-9]{34}"); + public static final Pattern callSidPattern = Pattern.compile("ID[a-zA-Z0-9]{32}-CA[a-zA-Z0-9]{32}"); + private final String id; + + public enum Type { + ACCOUNT, APPLICATION, ANNOUNCEMENT, CALL, CLIENT, CONFERENCE, GATEWAY, INVALID, NOTIFICATION, PHONE_NUMBER, RECORDING, REGISTRATION, SHORT_CODE, SMS_MESSAGE, TRANSCRIPTION, INSTANCE, EXTENSION_CONFIGURATION, GEOLOCATION, ORGANIZATION, PROFILE + }; + + private static final Sid INVALID_SID = new Sid("IN00000000000000000000000000000000"); + + public Sid(final String id) throws IllegalArgumentException { + super(); + //https://github.com/RestComm/Restcomm-Connect/issues/1907 + if (callSidPattern.matcher(id).matches() || pattern.matcher(id).matches()) { + this.id = id; + } else { + throw new IllegalArgumentException(id + " is an INVALID_SID sid value."); + } + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null) { + return false; + } + if (getClass() != object.getClass()) { + return false; + } + final Sid other = (Sid) object; + if (!toString().equals(other.toString())) { + return false; + } + return true; + } + + // Issue 108: https://bitbucket.org/telestax/telscale-restcomm/issue/108/account-sid-could-be-a-hash-of-the + public static Sid generate(final Type type, String string) { + String token = new Md5Hash(string).toString(); + switch (type) { + case ACCOUNT: { + return new Sid("AC" + token); + } + default: { + return generate(type); + } + } + } + + public static Sid generate(final Type type) { + final String uuid = UUID.randomUUID().toString().replace("-", ""); + switch (type) { + case ACCOUNT: { + return new Sid("AC" + uuid); + } + case APPLICATION: { + return new Sid("AP" + uuid); + } + case ANNOUNCEMENT: { + return new Sid("AN" + uuid); + } + case CALL: { + //https://github.com/RestComm/Restcomm-Connect/issues/1907 + return new Sid(RestcommConfiguration.getInstance().getMain().getInstanceId() + "-CA" + uuid); + } + case CLIENT: { + return new Sid("CL" + uuid); + } + case CONFERENCE: { + return new Sid("CF" + uuid); + } + case GATEWAY: { + return new Sid("GW" + uuid); + } + case INVALID: { + return INVALID_SID; + } + case NOTIFICATION: { + return new Sid("NO" + uuid); + } + case PHONE_NUMBER: { + return new Sid("PN" + uuid); + } + case RECORDING: { + return new Sid("RE" + uuid); + } + case REGISTRATION: { + return new Sid("RG" + uuid); + } + case SHORT_CODE: { + return new Sid("SC" + uuid); + } + case SMS_MESSAGE: { + return new Sid("SM" + uuid); + } + case TRANSCRIPTION: { + return new Sid("TR" + uuid); + } + case INSTANCE: { + return new Sid("ID" + uuid); + } + case EXTENSION_CONFIGURATION: { + return new Sid("EX" + uuid); + } + case GEOLOCATION: { + return new Sid("GL" + uuid); + } + case ORGANIZATION: { + return new Sid("OR" + uuid); + } + case PROFILE: { + return new Sid("PR" + uuid); + } + default: { + return null; + } + } + } + + @Override + public int hashCode() { + final int prime = 5; + int result = 1; + result = prime * result + id.hashCode(); + return result; + } + + @Override + public String toString() { + return id; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/exceptions/RestcommRuntimeException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/exceptions/RestcommRuntimeException.java new file mode 100644 index 0000000000..61fa7bf7f7 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/exceptions/RestcommRuntimeException.java @@ -0,0 +1,49 @@ +/* + * 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.exceptions; + +/** + * Generic type of runtime exception that is handled centrally using exceptions + * mappers. + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RestcommRuntimeException extends RuntimeException { + + public RestcommRuntimeException() { + } + + public RestcommRuntimeException(String message) { + super(message); + } + + public RestcommRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public RestcommRuntimeException(Throwable cause) { + super(cause); + } + + public RestcommRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisor.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisor.java new file mode 100644 index 0000000000..1ff5dba70b --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisor.java @@ -0,0 +1,105 @@ +package org.restcomm.connect.commons.faulttolerance; + +import akka.actor.ActorContext; +import akka.actor.ActorRef; +import akka.actor.ChildRestartStats; +import akka.actor.OneForOneStrategy; +import akka.actor.Props; +import akka.actor.StopChild; +import akka.actor.SupervisorStrategy; +import akka.actor.Terminated; +import akka.actor.UntypedActor; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import akka.japi.Function; +import scala.collection.Iterable; +import scala.concurrent.duration.Duration; + +import static akka.actor.SupervisorStrategy.resume; + +/** + * Created by gvagenas on 22/02/2017. + */ +@Deprecated +public class RestcommSupervisor extends UntypedActor { + + private LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + public RestcommSupervisor() {} + + + RestcommFaultToleranceStrategy defaultStrategy = new RestcommFaultToleranceStrategy(10, Duration.create("1 minute"), + new RestcommFaultToleranceDecider()); + + @Override + public void onReceive(Object msg) throws Exception { + try { + final Class klass = msg.getClass(); + final ActorRef sender = getSender(); + + if (logger.isInfoEnabled()) { + logger.info(" ********** RestcommSupervisor " + self().path() + " Processing Message: " + klass.getName()); + } + + if (msg instanceof Props) { + final ActorRef actor = getContext().actorOf((Props) msg); + getContext().watch(actor); + if (logger.isDebugEnabled()) { + logger.debug("Created and watching actor: " + actor.path().toString()); + } + sender.tell(actor, getSelf()); + } else if (msg instanceof Terminated) { + if (logger.isDebugEnabled()) { + logger.debug("Received Terminated message for actor {}", ((Terminated) msg).actor()); + } + } else if (msg instanceof StopChild) { + StopChild stop = (StopChild) msg; + final ActorRef child = stop.child(); + getContext().unwatch(child); + getContext().stop(child); + if (logger.isDebugEnabled()) { + String logmsg = String.format("RestcommSupervisor, actor %s stopped. Sender %s",child.path(), sender.path()); + logger.debug(logmsg); + } + } else { + unhandled(msg); + } + } catch (Exception e) { + logger.error("Exception during the OnReceive methid of RestcommSupervisor, {}", e); + } + } + + @Override // - 1st the actor will try to get the supervisor strategy + public SupervisorStrategy supervisorStrategy() { + ActorRef sender = getSender(); + return defaultStrategy; + } + + private class RestcommFaultToleranceStrategy extends OneForOneStrategy { + + public RestcommFaultToleranceStrategy(int maxNrOfRetries, Duration withinTimeRange, Function function) { + super(maxNrOfRetries, withinTimeRange, function); + } + + @Override // - 3rd the Supervisor Strategy will execute processFailure() method. Useful for cleanup or logging + public void processFailure(ActorContext context, boolean restart, ActorRef child, Throwable cause, ChildRestartStats stats, Iterable children) { + String msg = String.format("RestcommSupervisor, actor exception handling. Restart %s, actor path %s, cause %s,", restart, child.path().toString(), cause); + logger.error(msg); + super.processFailure(context, restart, child, cause, stats, children); + } + } + + private class RestcommFaultToleranceDecider implements Function { + + @Override + // - 2nd the Supervisor strategy will execute the Decider apply() to check what to do with the exception + public SupervisorStrategy.Directive apply(Throwable t) throws Exception { + logger.error("Handling exception {} will resume", t.getClass().getName()); + return resume(); +// return restart(); +// return stop(); +// return escalate(); + } + } + +} 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 new file mode 100644 index 0000000000..56c783b190 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisorStrategy.java @@ -0,0 +1,72 @@ +package org.restcomm.connect.commons.faulttolerance; + +import akka.actor.ActorContext; +import akka.actor.ActorRef; +import akka.actor.ChildRestartStats; +import akka.actor.OneForOneStrategy; +import akka.actor.SupervisorStrategy; +import akka.actor.SupervisorStrategyConfigurator; +import akka.japi.Function; +import org.apache.log4j.Logger; +import scala.collection.Iterable; +import scala.concurrent.duration.Duration; + +import static akka.actor.SupervisorStrategy.resume; + +/** + * Created by gvagenas on 01/04/2017. + */ +public class RestcommSupervisorStrategy implements SupervisorStrategyConfigurator { + + private static Logger logger = Logger.getLogger(RestcommSupervisorStrategy.class); + + static final SupervisorStrategy.Directive strategy = resume(); + + static RestcommFaultToleranceStrategy defaultStrategy = new RestcommFaultToleranceStrategy(10, Duration.create("1 minute"), + new RestcommFaultToleranceDecider()); + + @Override + public SupervisorStrategy create() { + return defaultStrategy; + } + + public static SupervisorStrategy getStrategy() { + return defaultStrategy; + } + + private static class RestcommFaultToleranceStrategy extends OneForOneStrategy { + + public RestcommFaultToleranceStrategy(int maxNrOfRetries, Duration withinTimeRange, Function function) { + super(maxNrOfRetries, withinTimeRange, function); + } + + @Override + public boolean handleFailure(ActorContext context, ActorRef child, Throwable cause, ChildRestartStats stats, Iterable children) { + String msg = String.format("RestcommSupervisorStrategy, actor exception handling. Actor path %s, exception cause %s, default exception handling strategy %s", child.path().toString(), cause, strategy.toString()); + logger.error(msg); + return super.handleFailure(context, child, cause, stats, children); + } + +// @Override // - 3rd the Supervisor Strategy will execute processFailure() method. Useful for cleanup or logging +// public void processFailure(ActorContext context, boolean restart, ActorRef child, Throwable cause, ChildRestartStats stats, Iterable children) { +// String msg = String.format("RestcommSupervisor, actor exception handling. Restart %s, actor path %s, cause %s,", restart, child.path().toString(), cause); +// logger.error(msg); +// super.processFailure(context, restart, child, cause, stats, children); +// } + } + + private static class RestcommFaultToleranceDecider implements Function { + + @Override + // - 2nd the Supervisor strategy will execute the Decider apply() to check what to do with the exception + public SupervisorStrategy.Directive apply(Throwable t) throws Exception { +// String msg = String.format("Handling exception %s with default strategy to %s", t.getClass().getName(), strategy.toString()); +// logger.error(msg); + return strategy; +// return resume(); +// return restart(); +// return stop(); +// return escalate(); + } + } +} 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/main/java/org/mobicents/servlet/restcomm/fsm/Action.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Action.java similarity index 95% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Action.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Action.java index ee00f2c643..f96cc10ea7 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Action.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Action.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/FiniteStateMachine.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/FiniteStateMachine.java similarity index 79% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/FiniteStateMachine.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/FiniteStateMachine.java index ba9314fdcc..efab625843 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/FiniteStateMachine.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/FiniteStateMachine.java @@ -17,16 +17,17 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; -import static com.google.common.base.Preconditions.*; -import com.google.common.collect.ImmutableMap; +import static com.google.common.base.Preconditions.checkNotNull; import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +import com.google.common.collect.ImmutableMap; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -35,6 +36,7 @@ public class FiniteStateMachine { private final ImmutableMap> transitions; private State state; + private TransitionEndListener transitionEndListener; public FiniteStateMachine(final State initial, final Set transitions) { super(); @@ -48,6 +50,10 @@ public State state() { return state; } + public void addTransitionEndListener(TransitionEndListener transitionEndListener) { + this.transitionEndListener = transitionEndListener; + } + public void transition(final Object event, final State target) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { checkNotNull(event, "The message passed can not be null."); @@ -69,6 +75,7 @@ public void transition(final Object event, final State target) throws Transition } } if (accept) { + // Execute action before leaving previous state (post-processing) final Action actionOnExit = state.getActionOnExit(); if (actionOnExit != null) { try { @@ -77,6 +84,8 @@ public void transition(final Object event, final State target) throws Transition throw new TransitionFailedException(exception, event, transition); } } + + // Execute action before entering new state (pre-processing) final Action actionOnEnter = target.getActionOnEnter(); if (actionOnEnter != null) { try { @@ -85,13 +94,30 @@ public void transition(final Object event, final State target) throws Transition throw new TransitionFailedException(exception, event, transition); } } + + // Move to a new state + State source = state; + state = target; + + // Execute action after entering new state (processing) + final Action actionOnState = target.getActionOnState(); + if (actionOnState != null) { + try { + actionOnState.execute(event); + } catch (final Exception exception) { + throw new TransitionFailedException(exception, event, transition); + } + } + + if (transitionEndListener != null) { + transitionEndListener.onTransitionEnd(source, target, event); + } } else { final StringBuilder buffer = new StringBuilder(); buffer.append("The condition guarding a transition from a(n) ").append(transition.getStateOnEnter().getId()) .append(" state to a(n) ").append(transition.getStateOnExit().getId()).append(" state has failed."); throw new TransitionRollbackException(buffer.toString(), event, transition); } - state = target; } private ImmutableMap> toImmutableMap(final Set transitions) { diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Guard.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Guard.java similarity index 95% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Guard.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Guard.java index 5b5b8b7431..34a88a49ae 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Guard.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Guard.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/State.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/State.java new file mode 100644 index 0000000000..89ba0604ec --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/State.java @@ -0,0 +1,97 @@ +/* + * 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.fsm; + +import static com.google.common.base.Preconditions.*; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public class State { + private final Action actionOnEnter; + private final Action actionOnState; + private final Action actionOnExit; + private final String id; + + public State(final String id, final Action actionOnEnter, final Action actionOnState, final Action actionOnExit) { + super(); + checkNotNull(id, "A state can not have a null value for id."); + this.actionOnEnter = actionOnEnter; + this.actionOnState = actionOnState; + this.actionOnExit = actionOnExit; + this.id = id; + } + + public State(final String id, final Action actionOnEnter, final Action actionOnExit) { + this(id, actionOnEnter, null, actionOnExit); + } + + public State(final String id, final Action actionOnState) { + this(id, null, actionOnState, null); + } + + @Override + public boolean equals(final Object object) { + if (object == null) { + return false; + } else if (this == object) { + return true; + } else if (getClass() != object.getClass()) { + return false; + } + final State state = (State) object; + if (!id.equals(state.getId())) { + return false; + } + return true; + } + + public Action getActionOnEnter() { + return actionOnEnter; + } + + public Action getActionOnState() { + return actionOnState; + } + + public Action getActionOnExit() { + return actionOnExit; + } + + public String getId() { + return id; + } + + @Override + public int hashCode() { + final int prime = 5; + int result = 1; + result = prime * result + id.hashCode(); + return result; + } + + @Override + public String toString() { + return id; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Transition.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Transition.java similarity index 95% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Transition.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Transition.java index 23aaf9db2d..22349c25b4 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/Transition.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/Transition.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; import static com.google.common.base.Preconditions.*; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionEndListener.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionEndListener.java new file mode 100644 index 0000000000..654717a019 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionEndListener.java @@ -0,0 +1,28 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2017, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it andor 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 OUT ANY WARRANTY; out 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 this program. If not, see + */ + +package org.restcomm.connect.commons.fsm; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public interface TransitionEndListener { + + void onTransitionEnd(State was, State is, Object event); +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionFailedException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionFailedException.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionFailedException.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionFailedException.java index bed43d1efa..2c0916d2e4 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionFailedException.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionFailedException.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionNotFoundException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionNotFoundException.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionNotFoundException.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionNotFoundException.java index 3bb98faa21..0d1f11c0b6 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionNotFoundException.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionNotFoundException.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionRollbackException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionRollbackException.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionRollbackException.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionRollbackException.java index 0af22445d8..83338fbdf3 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/fsm/TransitionRollbackException.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/fsm/TransitionRollbackException.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fsm; +package org.restcomm.connect.commons.fsm; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectFactory.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectFactory.java similarity index 97% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectFactory.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectFactory.java index b89be60992..ca84486616 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectFactory.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectFactory.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.loader; +package org.restcomm.connect.commons.loader; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectInstantiationException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectInstantiationException.java similarity index 96% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectInstantiationException.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectInstantiationException.java index 51f893fd37..19223ecfda 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/loader/ObjectInstantiationException.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/loader/ObjectInstantiationException.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.loader; +package org.restcomm.connect.commons.loader; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/AbstractObserverMessage.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/AbstractObserverMessage.java similarity index 90% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/AbstractObserverMessage.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/AbstractObserverMessage.java index 5224157cfa..fec6b10909 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/AbstractObserverMessage.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/AbstractObserverMessage.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; import akka.actor.ActorRef; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author thomas.quintana@telestax.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observe.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observe.java similarity index 89% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observe.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observe.java index 37d96c898f..c6eed191d2 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observe.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observe.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; import akka.actor.ActorRef; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author thomas.quintana@telestax.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observing.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observing.java similarity index 96% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observing.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observing.java index e5cf3ca05a..aaa98f64bb 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/Observing.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/Observing.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; import akka.actor.ActorRef; diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StandardResponse.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StandardResponse.java similarity index 88% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StandardResponse.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StandardResponse.java index d8de051f03..6453172e26 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StandardResponse.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StandardResponse.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author thomas.quintana@telestax.com (Thomas Quintana) @@ -31,6 +31,14 @@ public abstract class StandardResponse { private final String message; private final T object; + public StandardResponse() { + super(); + this.succeeded = true; + this.cause = null; + this.message = null; + this.object = null; + } + public StandardResponse(final T object) { super(); this.succeeded = true; diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StopObserving.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StopObserving.java similarity index 85% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StopObserving.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StopObserving.java index e46b2b5a50..c1d360ceba 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/StopObserving.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/StopObserving.java @@ -17,18 +17,23 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; import akka.actor.ActorRef; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author thomas.quintana@telestax.com (Thomas Quintana) */ @Immutable public final class StopObserving extends AbstractObserverMessage { + public StopObserving(final ActorRef observer) { super(observer); } + + public StopObserving() { + this(null); + } } diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/TooManyObserversException.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/TooManyObserversException.java similarity index 89% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/TooManyObserversException.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/TooManyObserversException.java index 5365bd4da6..fe1e04226e 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/patterns/TooManyObserversException.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/patterns/TooManyObserversException.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; public final class TooManyObserversException extends Exception { private static final long serialVersionUID = 1L; diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/push/PushNotificationServerHelper.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/push/PushNotificationServerHelper.java new file mode 100644 index 0000000000..14c05122f6 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/push/PushNotificationServerHelper.java @@ -0,0 +1,106 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.commons.push; + +import akka.actor.ActorSystem; +import akka.dispatch.Futures; +import com.google.gson.Gson; +import org.apache.commons.configuration.Configuration; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import scala.concurrent.ExecutionContext; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public class PushNotificationServerHelper { + + private static final Logger logger = Logger.getLogger(PushNotificationServerHelper.class); + + private final HttpClient httpClient = CustomHttpClientBuilder.buildDefaultClient(RestcommConfiguration.getInstance().getMain()); + + private final ExecutionContext dispatcher; + + private final boolean pushNotificationServerEnabled; + + private String pushNotificationServerUrl; + + private long pushNotificationServerDelay; + + + public PushNotificationServerHelper(final ActorSystem actorSystem, final Configuration configuration) { + this.dispatcher = actorSystem.dispatchers().lookup("restcomm-blocking-dispatcher"); + + final Configuration runtime = configuration.subset("runtime-settings"); + this.pushNotificationServerEnabled = runtime.getBoolean("push-notification-server-enabled", false); + if (this.pushNotificationServerEnabled) { + this.pushNotificationServerUrl = runtime.getString("push-notification-server-url"); + this.pushNotificationServerDelay = runtime.getLong("push-notification-server-delay"); + } + } + + public long sendPushNotificationIfNeeded(final String pushClientIdentity) { + if (!pushNotificationServerEnabled || pushClientIdentity == null) { + return 0; + } + if (logger.isDebugEnabled()) { + logger.debug("Push server notification to client with identity: '" + pushClientIdentity + "' added to queue."); + } + Futures.future(new Callable() { + + @Override + public Void call() throws Exception { + Map params = new HashMap<>(); + params.put("Identity", pushClientIdentity); + HttpPost httpPost = new HttpPost(pushNotificationServerUrl); + try { + httpPost.setEntity(new StringEntity(new Gson().toJson(params), ContentType.APPLICATION_JSON)); + if (logger.isDebugEnabled()) { + logger.debug("Sending push server notification to client with identity: " + pushClientIdentity); + } + HttpResponse httpResponse = httpClient.execute(httpPost); + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + logger.warn("Error while sending push server notification to client with identity: " + pushClientIdentity + ", response: " + httpResponse.getEntity()); + } + } catch (Exception e) { + logger.error("Exception while sending push server notification, " + e); + } finally { + httpPost.releaseConnection(); + } + return null; + } + }, dispatcher); + + return pushNotificationServerDelay; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/stream/StreamEvent.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/stream/StreamEvent.java new file mode 100644 index 0000000000..fa73f91e05 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/stream/StreamEvent.java @@ -0,0 +1,26 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2017, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it andor 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 OUT ANY WARRANTY; out 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 this program. If not, see + */ + +package org.restcomm.connect.commons.stream; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public interface StreamEvent { +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/CreateCallType.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/CreateCallType.java new file mode 100755 index 0000000000..31c9b996a7 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/CreateCallType.java @@ -0,0 +1,25 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.commons.telephony; + +public enum CreateCallType { + CLIENT, PSTN, SIP, USSD +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/ProxyRule.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/ProxyRule.java new file mode 100644 index 0000000000..4b5dfc5550 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/telephony/ProxyRule.java @@ -0,0 +1,35 @@ +package org.restcomm.connect.commons.telephony; + + +/** + * Created by gvagenas on 26/06/2017. + */ +public class ProxyRule { + private final String fromUri; + private final String toUri; + private final String username; + private final String password; + + public ProxyRule (final String fromUri, final String toUri, final String username, final String password) { + this.fromUri = fromUri; + this.toUri = toUri; + this.username = username; + this.password = password; + } + + public String getFromUri () { + return fromUri; + } + + public String getToUri () { + return toUri; + } + + public String getPassword () { + return password; + } + + public String getUsername () { + return username; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DNSUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DNSUtils.java new file mode 100644 index 0000000000..a77062fb46 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DNSUtils.java @@ -0,0 +1,65 @@ +/* + * 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.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.util.mock.InetAddressMock; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public class DNSUtils { + + private static boolean initialized = false; + + private static String dnsUtilImplClassName; + private static final String DEFAULT_DNS_UTIL_CLASS_NAME = "java.net.InetAddress"; + + public static void initializeDnsUtilImplClassName(Configuration conf) { + synchronized (DNSUtils.class) { + if (!initialized) { + String configClass = conf.getString("dns-util[@class]"); + dnsUtilImplClassName = (configClass == null || configClass.trim().equals("")) ? DEFAULT_DNS_UTIL_CLASS_NAME : configClass; + initialized = true; + } + } + } + + public static InetAddress getByName(String host) throws UnknownHostException { + InetAddress result = null; + switch (dnsUtilImplClassName) { + case "java.net.InetAddress": + result = InetAddress.getByName(host); + break; + /* we can add implementation of another dns impl as well, for example dn4j etc*/ + case "org.restcomm.connect.commons.util.mock.InetAddressMock": + //case "org.restcomm.connect.testsuite.mocks.InetAddressMock": + result = InetAddressMock.getByName(host); + break; + default: + result = InetAddress.getByName(host); + break; + } + return result == null ? InetAddress.getByName(host): result; + } +} \ No newline at end of file diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/DigestAuthentication.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DigestAuthentication.java similarity index 97% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/DigestAuthentication.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DigestAuthentication.java index bdd8daf5c8..c86a8f965b 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/DigestAuthentication.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/DigestAuthentication.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HexadecimalUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HexadecimalUtils.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HexadecimalUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HexadecimalUtils.java index 4fe32bcbad..fb4bf11de5 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HexadecimalUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HexadecimalUtils.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpConnectorDiscover.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpConnectorDiscover.java new file mode 100644 index 0000000000..13f7da0b1f --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpConnectorDiscover.java @@ -0,0 +1,34 @@ +/* + * 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.util; + +import java.net.UnknownHostException; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ReflectionException; +import org.restcomm.connect.commons.HttpConnectorList; + + +interface HttpConnectorDiscover { + HttpConnectorList findConnectors() throws MalformedObjectNameException, NullPointerException, UnknownHostException, AttributeNotFoundException, + InstanceNotFoundException, MBeanException, ReflectionException; +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HttpUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpUtils.java similarity index 96% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HttpUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpUtils.java index c988c3e99f..0bff89d5e1 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/HttpUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/HttpUtils.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; import java.io.IOException; import java.util.ArrayList; @@ -33,7 +33,7 @@ import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/IPUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/IPUtils.java similarity index 93% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/IPUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/IPUtils.java index faf8c076b0..8bfc9d6bc0 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/IPUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/IPUtils.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; import java.util.regex.Pattern; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/JBossConnectorDiscover.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/JBossConnectorDiscover.java new file mode 100644 index 0000000000..5f4afd71c6 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/JBossConnectorDiscover.java @@ -0,0 +1,87 @@ +/* + * 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.util; + +import java.lang.management.ManagementFactory; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Set; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.HttpConnector; +import org.restcomm.connect.commons.HttpConnectorList; + +public class JBossConnectorDiscover implements HttpConnectorDiscover { + + private static final Logger LOG = Logger.getLogger(JBossConnectorDiscover.class); + + /** + * A list of connectors. Not bound connectors will be discarded. + * + * @return + * @throws MalformedObjectNameException + * @throws NullPointerException + * @throws UnknownHostException + * @throws AttributeNotFoundException + * @throws InstanceNotFoundException + * @throws MBeanException + * @throws ReflectionException + */ + @Override + public HttpConnectorList findConnectors() throws MalformedObjectNameException, NullPointerException, UnknownHostException, AttributeNotFoundException, + InstanceNotFoundException, MBeanException, ReflectionException { + LOG.info("Searching JBoss HTTP connectors."); + HttpConnectorList httpConnectorList = null; + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + Set jbossObjs = mbs.queryNames(new ObjectName("jboss.as:socket-binding-group=standard-sockets,socket-binding=http*"), null); + LOG.info("JBoss Mbean found."); + ArrayList endPoints = new ArrayList(); + if (jbossObjs != null && jbossObjs.size() > 0) { + LOG.info("JBoss Connectors found:" + jbossObjs.size()); + for (ObjectName obj : jbossObjs) { + Boolean bound = (Boolean) mbs.getAttribute(obj, "bound"); + if (bound) { + String scheme = mbs.getAttribute(obj, "name").toString().replaceAll("\"", ""); + Integer port = (Integer) mbs.getAttribute(obj, "boundPort"); + String address = ((String) mbs.getAttribute(obj, "boundAddress")).replaceAll("\"", ""); + if (LOG.isInfoEnabled()) { + LOG.info("Jboss Http Connector: " + scheme + "://" + address + ":" + port); + } + HttpConnector httpConnector = new HttpConnector(scheme, address, port, scheme.equalsIgnoreCase("https")); + endPoints.add(httpConnector); + } else { + LOG.info("JBoss Connector not bound,discarding."); + } + } + } + if (endPoints.isEmpty()) { + LOG.warn("Coundn't discover any Http Interfaces."); + } + httpConnectorList = new HttpConnectorList(endPoints); + return httpConnectorList; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/PcmToWavConverterUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/PcmToWavConverterUtils.java new file mode 100644 index 0000000000..65017a4df9 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/PcmToWavConverterUtils.java @@ -0,0 +1,125 @@ +/* + * 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.util; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * @author ricardo.limonta@gmail.com (Ricardo Limonta) + */ +public class PcmToWavConverterUtils { + + public void rawToWave(final File rawFile, final File waveFile) throws IOException { + + byte[] rawData = new byte[(int) rawFile.length()]; + DataInputStream input = null; + try { + input = new DataInputStream(new FileInputStream(rawFile)); + input.read(rawData); + } finally { + if (input != null) { + input.close(); + } + } + + DataOutputStream output = null; + try { + output = new DataOutputStream(new FileOutputStream(waveFile)); + // WAVE header + writeString(output, "RIFF"); // chunk id + writeInt(output, 36 + rawData.length); // chunk size + writeString(output, "WAVE"); // format + writeString(output, "fmt "); // subchunk 1 id + writeInt(output, 16); // subchunk 1 size + writeShort(output, (short) 1); // audio format (1 = PCM) + writeShort(output, (short) 1); // number of channels + writeInt(output, 8000); // sample rate + writeInt(output, 8 * 2); // byte rate + writeShort(output, (short) 2); // block align + writeShort(output, (short) 16); // bits per sample + writeString(output, "data"); // subchunk 2 id + writeInt(output, rawData.length); // subchunk 2 size + // Audio data (conversion big endian -> little endian) + short[] shorts = new short[rawData.length / 2]; + ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts); + ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2); + for (short s : shorts) { + bytes.putShort(s); + } + + output.write(fullyReadFileToBytes(rawFile)); + } finally { + if (output != null) { + output.close(); + } + } + } + + byte[] fullyReadFileToBytes(File f) throws IOException { + int size = (int) f.length(); + byte[] bytes = new byte[size]; + byte[] tmpBuff = new byte[size]; + FileInputStream fis = new FileInputStream(f); + try { + + int read = fis.read(bytes, 0, size); + if (read < size) { + int remain = size - read; + while (remain > 0) { + read = fis.read(tmpBuff, 0, remain); + System.arraycopy(tmpBuff, 0, bytes, size - remain, read); + remain -= read; + } + } + } catch (IOException e) { + throw e; + } finally { + fis.close(); + } + + return bytes; + } + + private void writeInt(final DataOutputStream output, final int value) throws IOException { + output.write(value >> 0); + output.write(value >> 8); + output.write(value >> 16); + output.write(value >> 24); + } + + private void writeShort(final DataOutputStream output, final short value) throws IOException { + output.write(value >> 0); + output.write(value >> 8); + } + + private void writeString(final DataOutputStream output, final String value) throws IOException { + for (int i = 0; i < value.length(); i++) { + output.write(value.charAt(i)); + } + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/RevolvingCounter.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/RevolvingCounter.java similarity index 94% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/RevolvingCounter.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/RevolvingCounter.java index c1b1814098..2b3fcc0224 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/RevolvingCounter.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/RevolvingCounter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SdpUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SdpUtils.java new file mode 100644 index 0000000000..8cb053d3ef --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SdpUtils.java @@ -0,0 +1,168 @@ +package org.restcomm.connect.commons.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Vector; + +import javax.sdp.Connection; +import javax.sdp.MediaDescription; +import javax.sdp.Origin; +import javax.sdp.SdpException; +import javax.sdp.SdpFactory; +import javax.sdp.SdpParseException; +import javax.sdp.SessionDescription; + +//import ThreadSafe; + +/** + * @author Henrique Rosa (henrique.rosa@telestax.com) + */ +//@ThreadSafe +public class SdpUtils { + + /** + * Patches an SDP description by trimming and making sure it ends with a new line. + * + * @param sdpDescription The SDP description to be patched. + * @return The patched SDP description + * @author hrosa + */ + public static String endWithNewLine(String sdpDescription) { + if (sdpDescription == null || sdpDescription.isEmpty()) { + throw new IllegalArgumentException("The SDP description cannot be null or empty"); + } + return sdpDescription.trim().concat("\n"); + } + + @SuppressWarnings("unchecked") + public static String patch(final String contentType, final byte[] data, final String externalIp) + throws UnknownHostException, SdpException { + final String text = new String(data); + String patchedSdp = null; + if (contentType.equalsIgnoreCase("application/sdp")) { + final SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(text); + // Handle the connection at the session level. + fix(sdp.getConnection(), externalIp); + // https://github.com/Mobicents/RestComm/issues/149 + fix(sdp.getOrigin(), externalIp); + // Handle the connections at the media description level. + final Vector descriptions = sdp.getMediaDescriptions(false); + for (final MediaDescription description : descriptions) { + fix(description.getConnection(), externalIp); + } + patchedSdp = sdp.toString(); + } else { + String boundary = contentType.split(";")[1].split("=")[1]; + String[] parts = text.split(boundary); + String sdpText = null; + for (String part : parts) { + if (part.contains("application/sdp")) { + sdpText = part.replaceAll("Content.*", "").replaceAll("--", "").trim(); + } + } + final SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(sdpText); + fix(sdp.getConnection(), externalIp); + // https://github.com/Mobicents/RestComm/issues/149 + fix(sdp.getOrigin(), externalIp); + // Handle the connections at the media description level. + final Vector descriptions = sdp.getMediaDescriptions(false); + for (final MediaDescription description : descriptions) { + fix(description.getConnection(), externalIp); + } + patchedSdp = sdp.toString(); + } + return patchedSdp; + } + + public static String getSdp(final String contentType, final byte[] data) throws SdpParseException { + final String text = new String(data); + String sdpResult = null; + if (contentType.equalsIgnoreCase("application/sdp")) { + final SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(text); + sdpResult = sdp.toString(); + } else { + String boundary = contentType.split(";")[1].split("=")[1]; + String[] parts = text.split(boundary); + String sdpText = null; + for (String part : parts) { + if (part.contains("application/sdp")) { + sdpText = part.replaceAll("Content.*", "").replaceAll("--", "").trim(); + } + } + final SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(sdpText); + sdpResult = sdp.toString(); + } + return sdpResult; + } + + private static void fix(final Origin origin, final String externalIp) throws UnknownHostException, SdpException { + if (origin != null) { + if (Connection.IN.equals(origin.getNetworkType())) { + if (Connection.IP4.equals(origin.getAddressType())) { + final InetAddress address; + try { + address = DNSUtils.getByName(origin.getAddress()); + final String ip = address.getHostAddress(); + if (!IPUtils.isRoutableAddress(ip)) { + origin.setAddress(externalIp); + } + } catch (UnknownHostException e) { + // TODO do nothing cause domain name is unknown + // origin.setAddress(externalIp); to remove + } + } + } + } + } + + private static void fix(final Connection connection, final String externalIp) throws UnknownHostException, SdpException { + if (connection != null) { + if (Connection.IN.equals(connection.getNetworkType())) { + if (Connection.IP4.equals(connection.getAddressType())) { + final InetAddress address = DNSUtils.getByName(connection.getAddress()); + final String ip = address.getHostAddress(); + if (!IPUtils.isRoutableAddress(ip)) { + connection.setAddress(externalIp); + } + } + } + } + } + + public static boolean isWebRTCSDP(final String contentType, final byte[] data) throws SdpParseException { + boolean isWebRTC = false; + if (contentType.equalsIgnoreCase("application/sdp")) { + String sdp = getSdp(contentType, data); + if (sdp != null && sdp.contains("RTP/SAVP") || sdp.contains("rtp/savp") + || sdp.contains("RTP/SAVPF") || sdp.contains("rtp/savpf")) { + isWebRTC = true; + } + } + return isWebRTC; + } + + public static boolean isAudioSDP(final String contentType, final byte[] data) throws SdpParseException { + boolean isAudioSdp = false; + if (contentType.equalsIgnoreCase("application/sdp")) { + String sdp = getSdp(contentType, data); + if (sdp != null && sdp.contains("m=audio") || sdp.contains("m=AUDIO") + || sdp.contains("m=Audio")) { + isAudioSdp = true; + } + } + return isAudioSdp; + } + + public static boolean isVideoSDP(final String contentType, final byte[] data) throws SdpParseException { + boolean isVideoSdp = false; + if (contentType.equalsIgnoreCase("application/sdp")) { + String sdp = getSdp(contentType, data); + if (sdp != null && sdp.contains("m=video") || sdp.contains("m=VIDEO") + || sdp.contains("m=Video")) { + isVideoSdp = true; + } + } + return isVideoSdp; + } + +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SecurityUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SecurityUtils.java new file mode 100644 index 0000000000..7e39a47378 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/SecurityUtils.java @@ -0,0 +1,32 @@ +/* + * 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.util; + +import org.apache.commons.codec.binary.Base64; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class SecurityUtils { + public static String buildBasicAuthHeader(String username, String password) { + return "Basic " + Base64.encodeBase64String((username + ":" + password).getBytes()); + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/StringUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/StringUtils.java similarity index 94% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/StringUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/StringUtils.java index 763e07f42b..f4c371a39b 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/StringUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/StringUtils.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; import java.io.IOException; import java.io.InputStream; @@ -25,7 +25,7 @@ import java.io.StringWriter; import java.util.regex.Pattern; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/TimeUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TimeUtils.java similarity index 92% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/TimeUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TimeUtils.java index f3367edebc..d1079feb7e 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/TimeUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TimeUtils.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TomcatConnectorDiscover.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TomcatConnectorDiscover.java new file mode 100644 index 0000000000..1abe285ef2 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/TomcatConnectorDiscover.java @@ -0,0 +1,70 @@ +/* + * 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.util; + +import java.lang.management.ManagementFactory; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Set; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.Query; +import javax.management.ReflectionException; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.HttpConnector; +import org.restcomm.connect.commons.HttpConnectorList; + +public class TomcatConnectorDiscover implements HttpConnectorDiscover { + + private static final Logger LOG = Logger.getLogger(TomcatConnectorDiscover.class); + + @Override + public HttpConnectorList findConnectors() throws MalformedObjectNameException, NullPointerException, UnknownHostException, AttributeNotFoundException, + InstanceNotFoundException, MBeanException, ReflectionException { + LOG.info("Searching Tomcat HTTP connectors."); + HttpConnectorList httpConnectorList = null; + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + Set tomcatObjs = mbs.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))); + + ArrayList endPoints = new ArrayList(); + if (tomcatObjs != null && tomcatObjs.size() > 0) { + for (ObjectName obj : tomcatObjs) { + String scheme = mbs.getAttribute(obj, "scheme").toString().replaceAll("\"", ""); + String port = obj.getKeyProperty("port").replaceAll("\"", ""); + String address = obj.getKeyProperty("address").replaceAll("\"", ""); + if (LOG.isInfoEnabled()) { + LOG.info("Tomcat Http Connector: " + scheme + "://" + address + ":" + port); + } + HttpConnector httpConnector = new HttpConnector(scheme, address, Integer.parseInt(port), scheme.equalsIgnoreCase("https")); + endPoints.add(httpConnector); + } + } + if (endPoints.isEmpty()) { + LOG.warn("Coundn't discover any Http Interfaces"); + } + httpConnectorList = new HttpConnectorList(endPoints); + return httpConnectorList; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/UriUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/UriUtils.java new file mode 100644 index 0000000000..c6b18d266e --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/UriUtils.java @@ -0,0 +1,174 @@ +/* + * 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.util; + +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.List; + + +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.HttpConnector; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.HttpConnectorList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * Utility class to manipulate URI. + * + * @author Henrique Rosa + */ +@ThreadSafe +public final class UriUtils { + + private static Logger logger = Logger.getLogger(UriUtils.class); + private static HttpConnector selectedConnector = null; + + /** + * Default constructor. + */ + private UriUtils() { + super(); + } + + /** + * Resolves a relative URI. + * + * @param base The base of the URI + * @param uri The relative URI. + * @return The absolute URI + */ + public static URI resolve(final URI base, final URI uri) { + if (base.equals(uri)) { + return uri; + } else if (!uri.isAbsolute()) { + return base.resolve(uri); + } else { + return uri; + } + } + + /** + * Will query different JMX MBeans for a list of runtime connectors. + * + * JBoss discovery will be used first, then Tomcat. + * + * + * @return the list of connectors found + */ + private static HttpConnectorList getHttpConnectors() throws Exception { + logger.info("Searching HTTP connectors."); + HttpConnectorList httpConnectorList = null; + //find Jboss first as is typical setup + httpConnectorList = new JBossConnectorDiscover().findConnectors(); + if (httpConnectorList == null || httpConnectorList.getConnectors().isEmpty()) { + //if not found try tomcat + httpConnectorList = new TomcatConnectorDiscover().findConnectors(); + } + return httpConnectorList; + } + + /** + * Resolves a relative URI. + * + * @param uri The relative URI + * @return The absolute URI + */ + public static URI resolve(final URI uri) { + getHttpConnector(); + +// Since this is a relative URL that we are trying to resolve, we don't care about the public URL. +// //HttpConnector address could be a local address while the request came from a public address +// String address; +// if (httpConnector.getAddress().equalsIgnoreCase(localAddress)) { +// address = httpConnector.getAddress(); +// } else { +// address = localAddress; +// } + String restcommAddress = null; + if (RestcommConfiguration.getInstance().getMain().isUseHostnameToResolveRelativeUrls()) { + restcommAddress = RestcommConfiguration.getInstance().getMain().getHostname(); + if (restcommAddress == null || restcommAddress.isEmpty()) { + try { + InetAddress addr = DNSUtils.getByName(selectedConnector.getAddress()); + restcommAddress = addr.getCanonicalHostName(); + } catch (UnknownHostException e) { + logger.error("Unable to resolve: " + selectedConnector + " to hostname: " + e); + restcommAddress = selectedConnector.getAddress(); + } + } + } else { + restcommAddress = selectedConnector.getAddress(); + } + + String base = selectedConnector.getScheme() + "://" + restcommAddress + ":" + selectedConnector.getPort(); + try { + return resolve(new URI(base), uri); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Badly formed URI: " + base, e); + } + } + + /** + * For historical reasons this method never returns null, and instead + * throws a RuntimeException. + * + * TODO review all clients of this method to check for null instead of + * throwing RuntimeException + * + * @return The selected connector with Secure preference. + * @throws RuntimeException if no connector is found for some reason + */ + public static HttpConnector getHttpConnector() throws RuntimeException { + if (selectedConnector == null) { + try { + + HttpConnectorList httpConnectorList = getHttpConnectors(); + + if (httpConnectorList != null && !httpConnectorList.getConnectors().isEmpty()) { + List connectors = httpConnectorList.getConnectors(); + Iterator iterator = connectors.iterator(); + while (iterator.hasNext()) { + HttpConnector connector = iterator.next(); + //take secure conns with preference + if (connector.isSecure()) { + selectedConnector = connector; + } + } + if (selectedConnector == null) { + //if not secure,take the first one + selectedConnector = connectors.get(0); + } + } + + if (selectedConnector == null) { + //pervent logic to go further + throw new RuntimeException("No HttpConnector found"); + } + } catch (Exception e) { + throw new RuntimeException("Exception during HTTP Connectors discovery: ", e); + } + } + return selectedConnector; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/WavUtils.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/WavUtils.java similarity index 90% rename from restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/WavUtils.java rename to restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/WavUtils.java index 003820b94e..b7e15a2e58 100644 --- a/restcomm/restcomm.commons/src/main/java/org/mobicents/servlet/restcomm/util/WavUtils.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/WavUtils.java @@ -17,8 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.util; +package org.restcomm.connect.commons.util; +import java.io.EOFException; import java.io.File; import java.io.IOException; import java.net.URI; @@ -28,7 +29,7 @@ import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -58,7 +59,10 @@ public static double getAudioDuration(final File wavFile) throws UnsupportedAudi int sampleSize = 16; int channels = 1; return wavFile.length() / (sampleRate / 8.0) / sampleSize / channels; - } finally { + } catch (EOFException e) { + return 0; + } + finally { if (audio != null) { audio.close(); } diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/mock/InetAddressMock.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/mock/InetAddressMock.java new file mode 100644 index 0000000000..7b505c4bfd --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/util/mock/InetAddressMock.java @@ -0,0 +1,33 @@ +/* + * 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.util.mock; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public class InetAddressMock { + + public static InetAddress getByName(String host) throws UnknownHostException { + return InetAddress.getByName("127.0.0.1"); + } +} \ No newline at end of file diff --git a/restcomm/restcomm.commons/src/main/resources/org/mobicents/servlet/restcomm/release.properties b/restcomm/restcomm.commons/src/main/resources/org/mobicents/servlet/restcomm/release.properties deleted file mode 100644 index 3a14d7f4ff..0000000000 --- a/restcomm/restcomm.commons/src/main/resources/org/mobicents/servlet/restcomm/release.properties +++ /dev/null @@ -1,15 +0,0 @@ -# release.version correspons to the version currently in development. -# At the time of a public release of the version, -# the source repository has to be tagged with it and the property needs to increment in this file. -release.version=${pom.version} -release.revision=r${buildNumber} -release.date=${release.timestamp} -release.name=${mobicents.name} -release.disclaimer==\n\ - ==============================================================================\n\ - == ==\n\ - == Thank you for running Mobicents Restcomm Community code ==\n\ - == For Commercial Grade Support, please request a TelScale Subscription ==\n\ - == http://www.telestax.com/ ==\n\ - == ==\n\ - ==============================================================================\n\ diff --git a/restcomm/restcomm.commons/src/main/resources/org/restcomm/connect/commons/release.properties b/restcomm/restcomm.commons/src/main/resources/org/restcomm/connect/commons/release.properties new file mode 100644 index 0000000000..aa3653fb68 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/resources/org/restcomm/connect/commons/release.properties @@ -0,0 +1,27 @@ +# release.version correspons to the version currently in development. +# At the time of a public release of the version, +# the source repository has to be tagged with it and the property needs to increment in this file. +release.version=${pom.version} +release.revision=r${buildNumber} +release.date=${release.timestamp} +release.name=${name} +release.disclaimer==\n\ + ==============================================================================\n\ + == ==\n\ + == Thank you for running Restcomm-Connect Community code ==\n\ + == For Commercial Grade Support, please request a TelScale Subscription ==\n\ + == http://www.telestax.com/ ==\n\ + == ==\n\ + ==============================================================================\n\ + \n\ + ==============================================================================\n\ + == ==\n\ + == Restcomm-Connect ships with G.729 codec. ==\n\ + == G.729 includes patents from several companies and is licensed by ==\n\ + == Sipro Lab Telecom. Sipro Lab Telecom is the authorized Intellectual ==\n\ + == Property Licensing Administrator for G.729 technology and patent ==\n\ + == pool. In a number of countries, the use of G.729 may require ==\n\ + == a license fee and/or royalty fee. For more information please visit ==\n\ + == http://www.sipro.com/G-729.html ==\n\ + == ==\n\ + ==============================================================================\n\ diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/RecordingLengthTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/RecordingLengthTest.java new file mode 100644 index 0000000000..62bee8db11 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/RecordingLengthTest.java @@ -0,0 +1,36 @@ +package org.restcomm.connect.commons; + +import org.junit.Test; +import org.restcomm.connect.commons.util.WavUtils; + +import javax.sound.sampled.UnsupportedAudioFileException; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import static org.junit.Assert.assertEquals; + +public class RecordingLengthTest { + + @Test + public void testDuration() throws URISyntaxException, IOException, UnsupportedAudioFileException { + URI recordingFileUri = this.getClass().getClassLoader().getResource("test_recording.wav").toURI(); + File recordingFile = new File(recordingFileUri); + + double duration = WavUtils.getAudioDuration(recordingFile); + + assertEquals(12, duration, 1.0); + } + + @Test + public void testDuration2() throws URISyntaxException, IOException, UnsupportedAudioFileException { + URI recordingFileUri = this.getClass().getClassLoader().getResource("test_recording2.wav").toURI(); + File recordingFile = new File(recordingFileUri); + + double duration = WavUtils.getAudioDuration(recordingFile); + + assertEquals(19, duration, 1.0); + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/cache/DiskCacheTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/DiskCacheTest.java similarity index 91% rename from restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/cache/DiskCacheTest.java rename to restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/DiskCacheTest.java index 2103a01b69..2cf5b344ea 100644 --- a/restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/cache/DiskCacheTest.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/DiskCacheTest.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.cache; +package org.restcomm.connect.commons.cache; import static org.junit.Assert.assertTrue; @@ -27,8 +27,13 @@ import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; +import org.restcomm.connect.commons.cache.DiskCache; +import org.restcomm.connect.commons.cache.DiskCacheRequest; +import org.restcomm.connect.commons.cache.DiskCacheResponse; +import org.restcomm.connect.commons.cache.FileDownloader; import scala.concurrent.duration.FiniteDuration; import akka.actor.Actor; import akka.actor.ActorRef; @@ -40,6 +45,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ +@Ignore public final class DiskCacheTest { private ActorSystem system; private ActorRef cache; @@ -65,7 +71,7 @@ private ActorRef cache(final String location, final String uri) { @Override public Actor create() throws Exception { - return new DiskCache(location, uri); + return new DiskCache(new FileDownloader(), location, uri); } })); } diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/WavNoCacheTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/WavNoCacheTest.java new file mode 100644 index 0000000000..63ce03d54d --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/cache/WavNoCacheTest.java @@ -0,0 +1,101 @@ +package org.restcomm.connect.commons.cache; + +import akka.actor.Actor; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActorFactory; +import akka.testkit.TestActorRef; +import org.apache.commons.io.FileUtils; +import org.apache.shiro.crypto.hash.Sha256Hash; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.cache.DiskCache; +import org.restcomm.connect.commons.cache.DiskCacheRequest; +import org.restcomm.connect.commons.cache.FileDownloader; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.File; +import java.net.URI; + +/** + * @author Gennadiy Dubina + */ +public class WavNoCacheTest { + + private URI externalUrl = URI.create("http://external/file.wav"); + private String externalUrlHash = new Sha256Hash(externalUrl.toString()).toHex(); + + private String cacheUri = "http://127.0.0.1"; + private String cacheDir = "/tmp"; + private URI expectedLocal = URI.create(cacheUri + "/" + externalUrlHash + ".wav"); + + private FileDownloader downloader; + + private ActorSystem system; + + @Before + public void before() throws Exception { + downloader = Mockito.mock(FileDownloader.class); + system = ActorSystem.create(); + + //clean tmp dir + final File resultFile = new File(cacheDir + "/" + externalUrlHash + ".wav"); + if (resultFile.exists()) { + resultFile.delete(); + } + + Mockito.when(downloader.download(Mockito.any(URI.class), Mockito.any(File.class))).then(new Answer() { + @Override + public URI answer(InvocationOnMock invocationOnMock) throws Throwable { + FileUtils.copyFile(new File("src/test/resources/restcomm.xml"), resultFile); + return expectedLocal; + } + }); + } + + @After + public void after() throws Exception { + system.shutdown(); + } + + private DiskCache cache(final boolean cacheNo) { + final TestActorRef ref = TestActorRef.create(system, new Props(new UntypedActorFactory() { + + @Override + public Actor create() throws Exception { + return new DiskCache(downloader, cacheDir, cacheUri, true, cacheNo); + } + }), "test"); + return ref.underlyingActor(); + } + + @Test + public void testWavCached() throws Exception { + DiskCache cache = cache(false); + + URI response1 = cache.cache(new DiskCacheRequest(externalUrl)); + Assert.assertEquals(expectedLocal, response1); + + URI response2 = cache.cache(new DiskCacheRequest(externalUrl)); + Assert.assertEquals(expectedLocal, response2); + + Mockito.verify(downloader, Mockito.times(1)).download(Mockito.any(URI.class), Mockito.any(File.class)); + } + + @Test + public void testWavNoCached() throws Exception { + DiskCache cache = cache(true); + URI response1 = cache.cache(new DiskCacheRequest(externalUrl)); + Assert.assertEquals(externalUrl, response1); + + URI response2 = cache.cache(new DiskCacheRequest(externalUrl)); + Assert.assertEquals(externalUrl, response2); + + Mockito.verify(downloader, Mockito.never()).download(Mockito.any(URI.class), Mockito.any(File.class)); + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/CacheConfigurationTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/CacheConfigurationTest.java new file mode 100644 index 0000000000..b9412ce786 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/CacheConfigurationTest.java @@ -0,0 +1,67 @@ +package org.restcomm.connect.commons.configuration; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.configuration.sets.CacheConfigurationSet; + +import java.net.MalformedURLException; +import java.net.URL; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CacheConfigurationTest { + private static final String CACHE_PATH_VALUE = "${restcomm:home}/cache"; + private static final String CACHE_URI_VALUE = "http://127.0.0.1:8080/restcomm/cache"; + + private RestcommConfiguration defaultCfg; + private RestcommConfiguration enabledNoWavCacheCfg; + private RestcommConfiguration disabledNoWavCacheCfg; + + private RestcommConfiguration createCfg(final String cfgFileName) throws ConfigurationException, + MalformedURLException { + URL url = this.getClass().getResource(cfgFileName); + + Configuration xml = new XMLConfiguration(url); + return new RestcommConfiguration(xml); + } + + @Before + public void before() throws ConfigurationException, MalformedURLException { + defaultCfg = createCfg("/restcomm.xml"); + enabledNoWavCacheCfg = createCfg("/restcomm-cache-no-wav-true.xml"); + disabledNoWavCacheCfg = createCfg("/restcomm-cache-no-wav-false.xml"); + } + + public CacheConfigurationTest() { + super(); + } + + @Test + public void checkCacheSection() throws ConfigurationException, MalformedURLException { + CacheConfigurationSet cacheSet = defaultCfg.getCache(); + + assertTrue(CACHE_PATH_VALUE.equals(cacheSet.getCachePath())); + assertTrue(CACHE_URI_VALUE.equals(cacheSet.getCacheUri())); + } + + @Test + public void checkNoWavCacheFlagAbsenceInCfg() { + // the default value of "noWavCache" flag is "false" if tag doesn't present in *.xml + assertFalse(defaultCfg.getCache().isNoWavCache()); + } + + @Test + public void checkNoWavCacheFlagEnabledInCfg() { + assertTrue(enabledNoWavCacheCfg.getCache().isNoWavCache()); + } + + @Test + public void checkNoWavCacheFlagDisabledInCfg() { + assertFalse(disabledNoWavCacheCfg.getCache().isNoWavCache()); + } +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/ConfigurationSetTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/ConfigurationSetTest.java new file mode 100644 index 0000000000..42998b087c --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/ConfigurationSetTest.java @@ -0,0 +1,34 @@ +package org.restcomm.connect.commons.configuration; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.restcomm.connect.commons.configuration.sets.CustomConfigurationSet; +import org.restcomm.connect.commons.configuration.sources.EditableConfigurationSource; + +public class ConfigurationSetTest { + + public ConfigurationSetTest() { + // TODO Auto-generated constructor stub + } + + @Test + public void testValueRetrievalAndSetLifecycle() { + // + EditableConfigurationSource source = new EditableConfigurationSource(); + source.setProperty(CustomConfigurationSet.PROPERTY1_KEY, "value1"); + // test value retrieval + CustomConfigurationSet customSet = new CustomConfigurationSet(source); + assertTrue( customSet.getProperty1().equals("value1") ); + // make sure values are properly cached by the configuration set and are not changed when source changes + source.setProperty(CustomConfigurationSet.PROPERTY1_KEY, "changed_value1"); + assertTrue( customSet.getProperty1().equals("value1") ); + // test conf set lifecycle + RestcommConfiguration conf = new RestcommConfiguration(); + conf.addConfigurationSet("custom", customSet); + CustomConfigurationSet customSet2 = conf.get("custom",CustomConfigurationSet.class); + assertNotNull(customSet2); + assertTrue( customSet.getProperty1().equals("value1") ); + } + +} 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..609eabe5aa --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/MgAsrConfigurationTest.java @@ -0,0 +1,92 @@ +/* + * 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.*; + +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()); + } + + @Test + public void checkAsrMRT() throws ConfigurationException, MalformedURLException { + MgAsrConfigurationSet conf = createCfg("/restcomm.xml").getMgAsr(); + assertSame(60, conf.getAsrMRT()); + } + + @Test + public void checkDefaultGatheringTimeout() throws ConfigurationException, MalformedURLException { + MgAsrConfigurationSet conf = createCfg("/restcomm.xml").getMgAsr(); + assertSame(5, conf.getDefaultGatheringTimeout()); + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/RestcommConfigurationTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/RestcommConfigurationTest.java new file mode 100644 index 0000000000..872cafb7e3 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/RestcommConfigurationTest.java @@ -0,0 +1,72 @@ +package org.restcomm.connect.commons.configuration; + + +import java.net.InetSocketAddress; +import static org.junit.Assert.*; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; +import org.restcomm.connect.commons.common.http.SslMode; + +public class RestcommConfigurationTest { + private RestcommConfiguration conf; + private XMLConfiguration xml; + + public RestcommConfigurationTest() { + super(); + } + + @Before + public void before() throws ConfigurationException, MalformedURLException { + URL url = this.getClass().getResource("/restcomm.xml"); + // String relativePath = "../../../../../../../../restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml"; + xml = new XMLConfiguration(); + xml.setDelimiterParsingDisabled(true); + xml.setAttributeSplittingDisabled(true); + xml.load(url); + conf = new RestcommConfiguration(xml); + } + + @Test + public void allConfiguraitonSetsAreAvailable() { + assertNotNull(conf.getMain()); + // add new sets here ... + // ... + } + + // Test properties for the 'Main' configuration set + @Test + public void mainSetConfigurationOptionsAreValid() { + MainConfigurationSet main = conf.getMain(); + assertEquals(SslMode.strict, main.getSslMode()); + assertEquals("127.0.0.1", main.getHostname()); + assertTrue(main.isUseHostnameToResolveRelativeUrls()); + assertEquals(Integer.valueOf(200), main.getDefaultHttpMaxConns()); + assertEquals(Integer.valueOf(20), main.getDefaultHttpMaxConnsPerRoute()); + assertEquals(Integer.valueOf(30000), main.getDefaultHttpTTL()); + assertEquals(2, main.getDefaultHttpRoutes().size()); + InetSocketAddress addr1= new InetSocketAddress("127.0.0.1", 8080); + assertEquals(Integer.valueOf(10), main.getDefaultHttpRoutes().get(addr1)); + InetSocketAddress addr2= new InetSocketAddress("192.168.1.1", 80); + assertEquals(Integer.valueOf(60), main.getDefaultHttpRoutes().get(addr2)); + } + + @Test + public void validSingletonOperation() { + // make sure it is created + RestcommConfiguration.createOnce(xml); + RestcommConfiguration conf1 = RestcommConfiguration.getInstance(); + assertNotNull(conf1); + // make sure it's not created again for subsequent calls + RestcommConfiguration.createOnce(xml); + RestcommConfiguration conf2 = RestcommConfiguration.getInstance(); + assertTrue( conf1 == conf2 ); + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sets/CustomConfigurationSet.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sets/CustomConfigurationSet.java new file mode 100644 index 0000000000..7f548128ef --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sets/CustomConfigurationSet.java @@ -0,0 +1,20 @@ +package org.restcomm.connect.commons.configuration.sets; + +import org.restcomm.connect.commons.configuration.sets.impl.ConfigurationSet; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +public class CustomConfigurationSet extends ConfigurationSet { + + public static final String PROPERTY1_KEY = "property1"; + private String property1; + + public CustomConfigurationSet(ConfigurationSource source) { + super(source); + property1 = source.getProperty(PROPERTY1_KEY); + } + + public String getProperty1() { + return property1; + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sources/EditableConfigurationSource.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sources/EditableConfigurationSource.java new file mode 100644 index 0000000000..d491e772c3 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/sources/EditableConfigurationSource.java @@ -0,0 +1,61 @@ +/* + * 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.sources; + +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +import java.util.HashMap; +import java.util.Map; + +/* + * Mockup configuration source. Fill it up in your tests with values that simulate the actual source + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ +public class EditableConfigurationSource implements ConfigurationSource { + + Map properties = new HashMap(); + + public EditableConfigurationSource() { + // TODO Auto-generated constructor stub + } + + public Map getProperties() { + return properties; + } + + @Override + public String getProperty(String key) { + return properties.get(key); + } + + @Override + public String getProperty (String key, String defValue) { + String result = properties.get(key); + if (key == null || key.isEmpty()) + result = defValue; + return result; + } + + public void setProperty(String key, String value) { + properties.put(key, value); + } +} 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 new file mode 100644 index 0000000000..a80f4eb146 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/SupervisorActorCreationStressTest.java @@ -0,0 +1,74 @@ +package org.restcomm.connect.commons.faulttolerance; + +import static org.junit.Assert.assertTrue; + +import java.net.MalformedURLException; +import java.net.UnknownHostException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.apache.commons.configuration.ConfigurationException; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.restcomm.connect.commons.faulttolerance.tool.ActorCreatingThread; + +import akka.actor.ActorSystem; +import org.junit.Ignore; +import org.junit.experimental.categories.Category; + +import org.restcomm.connect.commons.annotations.WithInSecsTests; + +/** + * @author mariafarooq + * + */ +public class SupervisorActorCreationStressTest { + + protected static ActorSystem system; + + //nThreads the number of threads in the pool + private static final int nThreads = 150; + //we can increase decrease value of this to put less request to create actors from RestcommSupervisor + // each of this thread will ask RestcommSupervisor to create a SimpleActor + private static final int THREAD_COUNT = 300; + + public static AtomicInteger actorSuccessCount; + public static AtomicInteger actorFailureCount; + + @BeforeClass + public static void beforeClass() throws Exception { + Config config = ConfigFactory.load("akka_fault_tolerance_application.conf"); + system = ActorSystem.create("test", config ); + + actorSuccessCount = new AtomicInteger(); + actorFailureCount = new AtomicInteger(); + } + + @Test + @Category(value={WithInSecsTests.class}) + public void testCreateSampleAkkaActor() throws ConfigurationException, MalformedURLException, UnknownHostException, InterruptedException { + ExecutorService executor = Executors.newFixedThreadPool(nThreads); + for (int i = 0; i < THREAD_COUNT; i++) { + Runnable worker = new ActorCreatingThread(system); + executor.execute(worker); + } + executor.shutdown(); + // Wait until all threads are finish + while (!executor.isTerminated()) { + + } + Thread.sleep(THREAD_COUNT*2); + System.out.println("\nFinished all threads: \n actorSuccessCount: "+actorSuccessCount+"\nactorFailureCount: "+actorFailureCount); + assertTrue(actorFailureCount.get()==0); + assertTrue(actorSuccessCount.get()==THREAD_COUNT); + } + + @AfterClass + public static void afterClass() throws Exception { + system.shutdown(); + } +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/ActorCreatingThread.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/ActorCreatingThread.java new file mode 100644 index 0000000000..b0d93e794a --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/ActorCreatingThread.java @@ -0,0 +1,40 @@ +package org.restcomm.connect.commons.faulttolerance.tool; + +import akka.actor.Actor; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActorFactory; +import akka.testkit.JavaTestKit; + +/** + * @author mariafarooq + * + */ +public class ActorCreatingThread implements Runnable { + private final ActorSystem system; + + public ActorCreatingThread(final ActorSystem system){ + this.system = system; + } + + @Override + public void run() { + new JavaTestKit(system) { + { + final ActorRef self = getRef(); + + ActorRef actorCreator = system.actorOf(new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public Actor create() throws Exception { + return new MyUntypedActor(system); + } + })); + + actorCreator.tell(new String(), self); + }}; + } + +} 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 new file mode 100644 index 0000000000..22e018a867 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/MyUntypedActor.java @@ -0,0 +1,61 @@ +package org.restcomm.connect.commons.faulttolerance.tool; + +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.faulttolerance.SupervisorActorCreationStressTest; + +/** + * MyUntypedActor represent a restcomm-connect class that request supervisor to create actor for it + * + * @author mariafarooq + * + */ +public class MyUntypedActor extends RestcommUntypedActor { + private LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + private final ActorSystem system; + + public MyUntypedActor(final ActorSystem system){ + this.system = system; + } + + @Override + public void onReceive(Object message) throws Exception { + final Class klass = message.getClass(); + if (logger.isInfoEnabled()) { + logger.info(" ********** MyUntypedActor " + self().path() + " Processing Message: " + klass.getName()); + } + if (String.class.equals(klass)) { + if (logger.isInfoEnabled()) + logger.debug("create"); + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new SimpleActor(); + } + }); + ActorRef actorToBeCreated = null; + try { + actorToBeCreated = system.actorOf(props); + if (logger.isInfoEnabled()) + logger.debug("Actor created: "+actorToBeCreated.path()); + SupervisorActorCreationStressTest.actorSuccessCount.incrementAndGet(); + } catch (Exception e) { + SupervisorActorCreationStressTest.actorFailureCount.incrementAndGet(); + e.printStackTrace(); + logger.error("Problem during creation of actor: "+e); + } + } else { + unhandled(message); + } + } + +} 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 new file mode 100644 index 0000000000..d126731961 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/SimpleActor.java @@ -0,0 +1,19 @@ +package org.restcomm.connect.commons.faulttolerance.tool; + +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; + +/** + * SampleActor: a simple actor to be created + * + * @author mariafarooq + * + */ +public class SimpleActor extends RestcommUntypedActor { + + public SimpleActor(){ + } + + @Override + public void onReceive(Object message) throws Exception {} + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/patterns/ObserverPatternTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java similarity index 92% rename from restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/patterns/ObserverPatternTest.java rename to restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java index 3938b32d9e..1f60838767 100644 --- a/restcomm/restcomm.commons/src/test/java/org/mobicents/servlet/restcomm/patterns/ObserverPatternTest.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java @@ -17,25 +17,22 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.patterns; +package org.restcomm.connect.commons.patterns; 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.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.patterns.Observing; -import org.mobicents.servlet.restcomm.patterns.StopObserving; -import org.mobicents.servlet.restcomm.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.commons/src/test/java/org/restcomm/connect/commons/sid/SidTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/sid/SidTest.java new file mode 100644 index 0000000000..24e74f6c50 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/sid/SidTest.java @@ -0,0 +1,54 @@ +package org.restcomm.connect.commons.sid; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; + +public class SidTest { + + /** + * testSidConversion String to Sid conversation + */ + @Test + public void testSidConversion() { + String sidString = "AC6dcfdfd531e44ae4ac30e8f97e071ab2"; + try{ + Sid sid = new Sid(sidString); + assertTrue(sid != null); + }catch(Exception e){ + fail("invalid validation"); + } + } + + /** + * testNewCallSid: String to Sid conversation + */ + @Test + public void testNewCallSid() { + String sidString = "ID6dcfdfd531e44ae4ac30e8f97e071122-CA6dcfdfd531e44ae4ac30e8f97e071ab2"; + try{ + Sid sid = new Sid(sidString); + assertTrue(sid != null); + }catch(Exception e){ + fail("invalid validation"); + } + } + + /** + * testOldCallSid: it should be supported + * because from call api we can check older cdrs where sid was in old format + * and sid conversion should work + */ + @Test + public void testOldCallSid() { + String sidString = "CA6dcfdfd531e44ae4ac30e8f97e071ab2"; + try{ + Sid sid = new Sid(sidString); + assertTrue(sid != null); + }catch(Exception e){ + fail("invalid validation"); + } + } + +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/util/UriUtilsTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/util/UriUtilsTest.java new file mode 100644 index 0000000000..294aad9720 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/util/UriUtilsTest.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.util; + +import java.net.URI; +import org.junit.Test; + +public class UriUtilsTest { + + public UriUtilsTest() { + } + + @Test(expected = RuntimeException.class) + public void testNoConnector() throws Exception { + UriUtils.resolve(new URI("")); + } + +} diff --git a/restcomm/restcomm.commons/src/test/resources/akka_fault_tolerance_application.conf b/restcomm/restcomm.commons/src/test/resources/akka_fault_tolerance_application.conf new file mode 100644 index 0000000000..4cb1e4704d --- /dev/null +++ b/restcomm/restcomm.commons/src/test/resources/akka_fault_tolerance_application.conf @@ -0,0 +1,33 @@ +akka { + # Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT) +event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] + +# Log level used by the configured loggers (see "event-handlers") as soon +# as they have been started; before that, see "stdout-loglevel" +# Options: OFF, ERROR, WARNING, INFO, DEBUG +loglevel = "INFO" + +# Log level for the very basic logger activated during AkkaApplication startup +# Options: OFF, ERROR, WARNING, INFO, DEBUG +stdout-loglevel = "INFO" + +# Log the complete configuration at INFO level when the actor system is started. +# This is useful when you are uncertain of what configuration is used. +log-config-on-start = off + +# Configuration reference http://doc.akka.io/docs/akka/2.1.4/general/configuration.html + + actor { + + # The guardian "/user" will use this class to obtain its supervisorStrategy. + # It needs to be a subclass of akka.actor.SupervisorStrategyConfigurator. + # In addition to the default there is akka.actor.StoppingSupervisorStrategy. + guardian-supervisor-strategy = "org.restcomm.connect.commons.faulttolerance.RestcommSupervisorStrategy" + + # Timeout for ActorSystem.actorOf + # Default value 20s is too high + # creation-timeout = 20s + creation-timeout = 60s + } +} + diff --git a/restcomm/restcomm.commons/src/test/resources/restcomm-cache-no-wav-false.xml b/restcomm/restcomm.commons/src/test/resources/restcomm-cache-no-wav-false.xml new file mode 100644 index 0000000000..d079fbafa4 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/resources/restcomm-cache-no-wav-false.xml @@ -0,0 +1,386 @@ + + + + + + 2012-04-24 + + + true + + + http://127.0.0.1:8080/restcomm/audio + + + ${restcomm:home}/cache + http://127.0.0.1:8080/restcomm/cache + + + false + + + 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 + + + + + mms + +
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 + + + + + + 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-cache-no-wav-true.xml b/restcomm/restcomm.commons/src/test/resources/restcomm-cache-no-wav-true.xml new file mode 100644 index 0000000000..03d9b3b7af --- /dev/null +++ b/restcomm/restcomm.commons/src/test/resources/restcomm-cache-no-wav-true.xml @@ -0,0 +1,385 @@ + + + + + + 2012-04-24 + + + true + + + http://127.0.0.1:8080/restcomm/audio + + + ${restcomm:home}/cache + http://127.0.0.1:8080/restcomm/cache + + + true + + + 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 + + + + + mms + +
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 + + + + + + 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-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 new file mode 100644 index 0000000000..3ac1364b8c --- /dev/null +++ b/restcomm/restcomm.commons/src/test/resources/restcomm.xml @@ -0,0 +1,411 @@ + + + + + + 2012-04-24 + + + + en-US + en-GB + es-ES + it-IT + fr-FR + pl-PL + pt-PT + + + + + driver1 + driver2 + + + + 60 + + + 5 + + + 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 + + 200 + 20 + 30000 + 127.0.0.1,192.168.1.1 + 8080,80 + 10,60 + + + + + + 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.rvd/src/main/webapp/protoProjects/_proto_ussd/data/.forgit b/restcomm/restcomm.commons/src/test/resources/supervisor-stress.conf similarity index 100% rename from restcomm/restcomm.rvd/src/main/webapp/protoProjects/_proto_ussd/data/.forgit rename to restcomm/restcomm.commons/src/test/resources/supervisor-stress.conf diff --git a/restcomm/restcomm.commons/src/test/resources/test_recording.wav b/restcomm/restcomm.commons/src/test/resources/test_recording.wav new file mode 100644 index 0000000000..f84da47ce2 Binary files /dev/null and b/restcomm/restcomm.commons/src/test/resources/test_recording.wav differ diff --git a/restcomm/restcomm.commons/src/test/resources/test_recording2.wav b/restcomm/restcomm.commons/src/test/resources/test_recording2.wav new file mode 100644 index 0000000000..d6ca92e341 Binary files /dev/null and b/restcomm/restcomm.commons/src/test/resources/test_recording2.wav differ diff --git a/restcomm/restcomm.dao/.settings/org.eclipse.core.resources.prefs b/restcomm/restcomm.dao/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..29abf99956 --- /dev/null +++ b/restcomm/restcomm.dao/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/restcomm/restcomm.dao/.settings/org.eclipse.m2e.core.prefs b/restcomm/restcomm.dao/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000000..f897a7f1cb --- /dev/null +++ b/restcomm/restcomm.dao/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/restcomm/restcomm.dao/pom.xml b/restcomm/restcomm.dao/pom.xml index 1241c51dae..e47408da08 100644 --- a/restcomm/restcomm.dao/pom.xml +++ b/restcomm/restcomm.dao/pom.xml @@ -1,15 +1,16 @@ - + 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.dao - restcomm.dao + restcomm-connect.dao + restcomm-connect.dao http://maven.apache.org @@ -42,35 +43,77 @@ org.mongodb mongo-java-driver - + org.apache.shiro shiro-core - + org.apache.shiro shiro-web - + - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons ${project.version} provided - + + + org.restcomm + restcomm-connect.extension.api + ${project.version} + provided + + + + org.apache.tomcat + tomcat-coyote + provided + + + + org.mobicents.servlet.sip.containers + sip-servlets-catalina-7 + provided + + + + com.googlecode.libphonenumber + libphonenumber + + junit junit test - + - hsqldb + org.hsqldb hsqldb - test + + + com.google.code.gson + gson + ${gson.version} + + + + diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AccountsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AccountsDao.java deleted file mode 100644 index 2ec58064f2..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AccountsDao.java +++ /dev/null @@ -1,42 +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.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface AccountsDao { - void addAccount(Account account); - - Account getAccount(Sid sid); - - Account getAccount(String name); - - List getAccounts(Sid sid); - - void removeAccount(Sid sid); - - void updateAccount(Account account); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AnnouncementsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AnnouncementsDao.java deleted file mode 100644 index bc40ef5d5c..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AnnouncementsDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.mobicents.servlet.restcomm.entities.Announcement; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author George Vagenas - */ - -public interface AnnouncementsDao { - void addAnnouncement(Announcement announcement); - - Announcement getAnnouncement(Sid sid); - - List getAnnouncements(Sid accountSid); - - void removeAnnouncement(Sid sid); - - void removeAnnouncements(Sid accountSid); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/CallDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/CallDetailRecordsDao.java deleted file mode 100644 index fef513e80b..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/CallDetailRecordsDao.java +++ /dev/null @@ -1,59 +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.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordFilter; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface CallDetailRecordsDao { - void addCallDetailRecord(CallDetailRecord cdr); - - CallDetailRecord getCallDetailRecord(Sid sid); - - List getCallDetailRecords(Sid accountSid); - - List getCallDetailRecordsByRecipient(String recipient); - - List getCallDetailRecordsBySender(String sender); - - List getCallDetailRecordsByStatus(String status); - - List getCallDetailRecordsByStartTime(DateTime startTime); - - List getCallDetailRecordsByParentCall(Sid parentCallSid); - - void removeCallDetailRecord(Sid sid); - - void removeCallDetailRecords(Sid accountSid); - - void updateCallDetailRecord(CallDetailRecord cdr); - - // Support for filtering of calls list result, Issue 153 - List getCallDetailRecords(CallDetailRecordFilter filter); - - Integer getTotalCallDetailRecords(CallDetailRecordFilter filter); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoManager.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoManager.java deleted file mode 100644 index 8680cef79e..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoManager.java +++ /dev/null @@ -1,60 +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.mobicents.servlet.restcomm.dao; - -import org.mobicents.servlet.restcomm.Configurable; -import org.mobicents.servlet.restcomm.LifeCycle; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface DaoManager extends Configurable, LifeCycle { - AccountsDao getAccountsDao(); - - ApplicationsDao getApplicationsDao(); - - AnnouncementsDao getAnnouncementsDao(); - - AvailablePhoneNumbersDao getAvailablePhoneNumbersDao(); - - CallDetailRecordsDao getCallDetailRecordsDao(); - - ClientsDao getClientsDao(); - - HttpCookiesDao getHttpCookiesDao(); - - IncomingPhoneNumbersDao getIncomingPhoneNumbersDao(); - - NotificationsDao getNotificationsDao(); - - OutgoingCallerIdsDao getOutgoingCallerIdsDao(); - - RegistrationsDao getRegistrationsDao(); - - RecordingsDao getRecordingsDao(); - - ShortCodesDao getShortCodesDao(); - - SmsMessagesDao getSmsMessagesDao(); - - TranscriptionsDao getTranscriptionsDao(); - - GatewaysDao getGatewaysDao(); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoUtils.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoUtils.java deleted file mode 100644 index f110833fe0..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/DaoUtils.java +++ /dev/null @@ -1,186 +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.mobicents.servlet.restcomm.dao; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.Currency; -import java.util.Date; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class DaoUtils { - private DaoUtils() { - super(); - } - - public static Account.Status readAccountStatus(final Object object) { - if (object != null) { - return Account.Status.getValueOf((String) object); - } else { - return null; - } - } - - public static Account.Type readAccountType(final Object object) { - if (object != null) { - return Account.Type.getValueOf((String) object); - } else { - return null; - } - } - - public static BigDecimal readBigDecimal(final Object object) { - if (object != null) { - return new BigDecimal((String) object); - } else { - return null; - } - } - - public static Boolean readBoolean(final Object object) { - if (object != null) { - return (Boolean) object; - } else { - return null; - } - } - - public static DateTime readDateTime(final Object object) { - if (object != null) { - return new DateTime((Date) object); - } else { - return null; - } - } - - public static Double readDouble(final Object object) { - if (object != null) { - return (Double) object; - } else { - return null; - } - } - - public static Integer readInteger(final Object object) { - if (object != null) { - return (Integer) object; - } else { - return null; - } - } - - public static Long readLong(final Object object) { - if (object != null) { - return (Long) object; - } else { - return null; - } - } - - public static Sid readSid(final Object object) { - if (object != null) { - return new Sid((String) object); - } else { - return null; - } - } - - public static String readString(final Object object) { - if (object != null) { - return (String) object; - } else { - return null; - } - } - - public static URI readUri(final Object object) { - if (object != null) { - return URI.create((String) object); - } else { - return null; - } - } - - public static Currency readCurrency(final Object object) { - if (object != null) { - return Currency.getInstance((String) object); - } else { - return null; - } - } - - public static String writeAccountStatus(final Account.Status status) { - return status.toString(); - } - - public static String writeAccountType(final Account.Type type) { - return type.toString(); - } - - public static String writeBigDecimal(final BigDecimal bigDecimal) { - if (bigDecimal != null) { - return bigDecimal.toString(); - } else { - return null; - } - } - - public static Date writeDateTime(final DateTime dateTime) { - if (dateTime != null) { - return dateTime.toDate(); - } else { - return null; - } - } - - public static String writeSid(final Sid sid) { - if (sid != null) { - return sid.toString(); - } else { - return null; - } - } - - public static String writeUri(final URI uri) { - if (uri != null) { - return uri.toString(); - } else { - return null; - } - } - - public static String writeCurrency(final Currency currency) { - if (currency != null) { - return currency.getCurrencyCode(); - } else { - return null; - } - } - -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RecordingsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RecordingsDao.java deleted file mode 100644 index f6d4990bbb..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RecordingsDao.java +++ /dev/null @@ -1,42 +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.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.mobicents.servlet.restcomm.entities.Recording; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface RecordingsDao { - void addRecording(Recording recording); - - Recording getRecording(Sid sid); - - Recording getRecordingByCall(Sid callSid); - - List getRecordings(Sid accountSid); - - void removeRecording(Sid sid); - - void removeRecordings(Sid accountSid); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RegistrationsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RegistrationsDao.java deleted file mode 100644 index 6e1b4a7630..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/RegistrationsDao.java +++ /dev/null @@ -1,41 +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.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.mobicents.servlet.restcomm.entities.Registration; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface RegistrationsDao { - void addRegistration(Registration registration); - - Registration getRegistration(String user); - - List getRegistrations(); - - boolean hasRegistration(Registration registration); - - void removeRegistration(Registration registration); - - void updateRegistration(Registration registration); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/SmsMessagesDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/SmsMessagesDao.java deleted file mode 100644 index 7a42f4850c..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/SmsMessagesDao.java +++ /dev/null @@ -1,42 +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.mobicents.servlet.restcomm.dao; - -import java.util.List; - -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public interface SmsMessagesDao { - void addSmsMessage(SmsMessage smsMessage); - - SmsMessage getSmsMessage(Sid sid); - - List getSmsMessages(Sid accountSid); - - void removeSmsMessage(Sid sid); - - void removeSmsMessages(Sid accountSid); - - void updateSmsMessage(SmsMessage smsMessage); -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAccountsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAccountsDao.java deleted file mode 100644 index bc61914e18..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAccountsDao.java +++ /dev/null @@ -1,175 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisAccountsDao implements AccountsDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.AccountsDao."; - private final SqlSessionFactory sessions; - - public MybatisAccountsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addAccount(final Account account) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addAccount", toMap(account)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public Account getAccount(final Sid sid) { - return getAccount(namespace + "getAccount", sid.toString()); - } - - @Override - public Account getAccount(final String name) { - Account account = null; - - account = getAccount(namespace + "getAccountByFriendlyName", name); - if (account == null){ - account = getAccount(namespace + "getAccountByEmail", name); - } - if (account == null) { - account = getAccount(namespace + "getAccount", name); - } - - return account; - } - - private Account getAccount(final String selector, final Object parameters) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(selector, parameters); - if (result != null) { - return toAccount(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getAccounts(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getAccounts", accountSid.toString()); - final List accounts = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - accounts.add(toAccount(result)); - } - } - return accounts; - } finally { - session.close(); - } - } - - @Override - public void removeAccount(final Sid sid) { - removeAccount(namespace + "removeAccount", sid); - } - - private void removeAccount(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateAccount(final Account account) { - updateAccount(namespace + "updateAccount", account); - } - - private void updateAccount(final String selector, final Account account) { - final SqlSession session = sessions.openSession(); - try { - session.update(selector, toMap(account)); - session.commit(); - } finally { - session.close(); - } - } - - private Account toAccount(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String emailAddress = readString(map.get("email_address")); - final String friendlyName = readString(map.get("friendly_name")); - final Sid accountSid = readSid(map.get("account_sid")); - final Account.Type type = readAccountType(map.get("type")); - final Account.Status status = readAccountStatus(map.get("status")); - final String authToken = readString(map.get("auth_token")); - final String role = readString(map.get("role")); - final URI uri = readUri(map.get("uri")); - return new Account(sid, dateCreated, dateUpdated, emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - private Map toMap(final Account account) { - final Map map = new HashMap(); - map.put("sid", writeSid(account.getSid())); - map.put("date_created", writeDateTime(account.getDateCreated())); - map.put("date_updated", writeDateTime(account.getDateUpdated())); - map.put("email_address", account.getEmailAddress()); - map.put("friendly_name", account.getFriendlyName()); - map.put("account_sid", writeSid(account.getAccountSid())); - map.put("type", writeAccountType(account.getType())); - map.put("status", writeAccountStatus(account.getStatus())); - map.put("auth_token", account.getAuthToken()); - map.put("role", account.getRole()); - map.put("uri", writeUri(account.getUri())); - return map; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisApplicationsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisApplicationsDao.java deleted file mode 100644 index 4b4c9d4781..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisApplicationsDao.java +++ /dev/null @@ -1,174 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.dao.ApplicationsDao; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.entities.Application; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisApplicationsDao implements ApplicationsDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ApplicationsDao."; - private final SqlSessionFactory sessions; - - public MybatisApplicationsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addApplication(final Application application) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addApplication", toMap(application)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public Application getApplication(final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(namespace + "getApplication", sid.toString()); - if (result != null) { - return toApplication(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getApplications(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getApplications", accountSid.toString()); - final List applications = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - applications.add(toApplication(result)); - } - } - return applications; - } finally { - session.close(); - } - } - - @Override - public void removeApplication(final Sid sid) { - removeApplications("removeApplication", sid); - } - - @Override - public void removeApplications(final Sid accountSid) { - removeApplications("removeApplications", accountSid); - } - - private void removeApplications(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(namespace + selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateApplication(final Application application) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateApplication", toMap(application)); - session.commit(); - } finally { - session.close(); - } - } - - private Application toApplication(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String friendlyName = readString(map.get("friendly_name")); - final Sid accountSid = readSid(map.get("account_sid")); - final String apiVersion = readString(map.get("api_version")); - final URI voiceUrl = readUri(map.get("voice_url")); - final String voiceMethod = readString(map.get("voice_method")); - final URI voiceFallbackUrl = readUri(map.get("voice_fallback_url")); - final String voiceFallbackMethod = readString(map.get("voice_fallback_method")); - final URI statusCallback = readUri(map.get("status_callback")); - final String statusCallbackMethod = readString(map.get("status_callback_method")); - final Boolean hasVoiceCallerIdLookup = readBoolean(map.get("voice_caller_id_lookup")); - final URI smsUrl = readUri(map.get("sms_url")); - final String smsMethod = readString(map.get("sms_method")); - final URI smsFallbackUrl = readUri(map.get("sms_fallback_url")); - final String smsFallbackMethod = readString(map.get("sms_fallback_method")); - final URI smsStatusCallback = readUri(map.get("sms_status_callback")); - final URI uri = readUri(map.get("uri")); - return new Application(sid, dateCreated, dateUpdated, friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - private Map toMap(final Application application) { - final Map map = new HashMap(); - map.put("sid", writeSid(application.getSid())); - map.put("date_created", writeDateTime(application.getDateCreated())); - map.put("date_updated", writeDateTime(application.getDateUpdated())); - map.put("friendly_name", application.getFriendlyName()); - map.put("account_sid", writeSid(application.getAccountSid())); - map.put("api_version", application.getApiVersion()); - map.put("voice_url", writeUri(application.getVoiceUrl())); - map.put("voice_method", application.getVoiceMethod()); - map.put("voice_fallback_url", writeUri(application.getVoiceFallbackUrl())); - map.put("voice_fallback_method", application.getVoiceFallbackMethod()); - map.put("status_callback", writeUri(application.getStatusCallback())); - map.put("status_callback_method", application.getStatusCallbackMethod()); - map.put("voice_caller_id_lookup", application.hasVoiceCallerIdLookup()); - map.put("sms_url", writeUri(application.getSmsUrl())); - map.put("sms_method", application.getSmsMethod()); - map.put("sms_fallback_url", writeUri(application.getSmsFallbackUrl())); - map.put("sms_fallback_method", application.getSmsFallbackMethod()); - map.put("sms_status_callback", writeUri(application.getSmsStatusCallback())); - map.put("uri", writeUri(application.getUri())); - return map; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisCallDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisCallDetailRecordsDao.java deleted file mode 100644 index 1642c9d778..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisCallDetailRecordsDao.java +++ /dev/null @@ -1,246 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.ArrayList; -import java.util.Currency; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; - -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordFilter; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisCallDetailRecordsDao implements CallDetailRecordsDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.CallDetailRecordsDao."; - private final SqlSessionFactory sessions; - - public MybatisCallDetailRecordsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addCallDetailRecord(final CallDetailRecord cdr) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addCallDetailRecord", toMap(cdr)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public CallDetailRecord getCallDetailRecord(final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(namespace + "getCallDetailRecord", sid.toString()); - if (result != null) { - return toCallDetailRecord(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - // Issue 110 - @Override - public Integer getTotalCallDetailRecords(CallDetailRecordFilter filter) { - - final SqlSession session = sessions.openSession(); - try { - final Integer total = session.selectOne(namespace + "getTotalCallDetailRecordByUsingFilters", filter); - return total; - } finally { - session.close(); - } - - } - - // Issue 153: https://bitbucket.org/telestax/telscale-restcomm/issue/153 - // Issue 110: https://bitbucket.org/telestax/telscale-restcomm/issue/110 - @Override - public List getCallDetailRecords(CallDetailRecordFilter filter) { - - final SqlSession session = sessions.openSession(); - - try { - final List> results = session.selectList(namespace + "getCallDetailRecordByUsingFilters", - filter); - final List cdrs = new ArrayList(); - - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - cdrs.add(toCallDetailRecord(result)); - } - } - return cdrs; - } finally { - session.close(); - } - } - - @Override - public List getCallDetailRecords(final Sid accountSid) { - return getCallDetailRecords(namespace + "getCallDetailRecords", accountSid.toString()); - } - - @Override - public List getCallDetailRecordsByRecipient(final String recipient) { - return getCallDetailRecords(namespace + "getCallDetailRecordsByRecipient", recipient); - } - - @Override - public List getCallDetailRecordsBySender(final String sender) { - return getCallDetailRecords(namespace + "getCallDetailRecordsBySender", sender); - } - - @Override - public List getCallDetailRecordsByStatus(final String status) { - return getCallDetailRecords(namespace + "getCallDetailRecordsByStatus", status); - } - - @Override - public List getCallDetailRecordsByStartTime(final DateTime startTime) { - return getCallDetailRecords(namespace + "getCallDetailRecordsByStartTime", startTime.toDate()); - } - - @Override - public List getCallDetailRecordsByParentCall(final Sid parentCallSid) { - return getCallDetailRecords(namespace + "getCallDetailRecordsByParentCall", parentCallSid.toString()); - } - - private List getCallDetailRecords(final String selector, Object input) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(selector, input); - final List cdrs = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - cdrs.add(toCallDetailRecord(result)); - } - } - return cdrs; - } finally { - session.close(); - } - } - - @Override - public void removeCallDetailRecord(final Sid sid) { - removeCallDetailRecords(namespace + "removeCallDetailRecord", sid); - } - - @Override - public void removeCallDetailRecords(final Sid accountSid) { - removeCallDetailRecords(namespace + "removeCallDetailRecords", accountSid); - } - - private void removeCallDetailRecords(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateCallDetailRecord(final CallDetailRecord cdr) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateCallDetailRecord", toMap(cdr)); - session.commit(); - } finally { - session.close(); - } - } - - private CallDetailRecord toCallDetailRecord(final Map map) { - final Sid sid = readSid(map.get("sid")); - final Sid parentCallSid = readSid(map.get("parent_call_sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final Sid accountSid = readSid(map.get("account_sid")); - final String to = readString(map.get("recipient")); - final String from = readString(map.get("sender")); - final Sid phoneNumberSid = readSid(map.get("phone_number_sid")); - final String status = readString(map.get("status")); - final DateTime startTime = readDateTime(map.get("start_time")); - final DateTime endTime = readDateTime(map.get("end_time")); - final Integer duration = readInteger(map.get("duration")); - final BigDecimal price = readBigDecimal(map.get("price")); - final Currency priceUnit = readCurrency(map.get("price_unit")); - final String direction = readString(map.get("direction")); - final String answeredBy = readString(map.get("answered_by")); - final String apiVersion = readString(map.get("api_version")); - final String forwardedFrom = readString(map.get("forwarded_from")); - final String callerName = readString(map.get("caller_name")); - final URI uri = readUri(map.get("uri")); - final String callPath = readString(map.get("call_path")); - return new CallDetailRecord(sid, parentCallSid, dateCreated, dateUpdated, accountSid, to, from, phoneNumberSid, status, - startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, callerName, - uri, callPath); - } - - private Map toMap(final CallDetailRecord cdr) { - final Map map = new HashMap(); - map.put("sid", writeSid(cdr.getSid())); - map.put("parent_call_sid", writeSid(cdr.getParentCallSid())); - map.put("date_created", writeDateTime(cdr.getDateCreated())); - map.put("date_updated", writeDateTime(cdr.getDateUpdated())); - map.put("account_sid", writeSid(cdr.getAccountSid())); - map.put("to", cdr.getTo()); - map.put("from", cdr.getFrom()); - map.put("phone_number_sid", writeSid(cdr.getPhoneNumberSid())); - map.put("status", cdr.getStatus()); - map.put("start_time", writeDateTime(cdr.getStartTime())); - map.put("end_time", writeDateTime(cdr.getEndTime())); - map.put("duration", cdr.getDuration()); - map.put("price", writeBigDecimal(cdr.getPrice())); - map.put("direction", cdr.getDirection()); - map.put("answered_by", cdr.getAnsweredBy()); - map.put("api_version", cdr.getApiVersion()); - map.put("forwarded_from", cdr.getForwardedFrom()); - map.put("caller_name", cdr.getCallerName()); - map.put("uri", writeUri(cdr.getUri())); - map.put("call_path", cdr.getCallPath()); - return map; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisDaoManager.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisDaoManager.java deleted file mode 100644 index 951a3c4219..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisDaoManager.java +++ /dev/null @@ -1,209 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.Reader; -import java.util.Properties; - -import org.apache.commons.configuration.Configuration; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; - -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.AnnouncementsDao; -import org.mobicents.servlet.restcomm.dao.ApplicationsDao; -import org.mobicents.servlet.restcomm.dao.AvailablePhoneNumbersDao; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.dao.ClientsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.GatewaysDao; -import org.mobicents.servlet.restcomm.dao.HttpCookiesDao; -import org.mobicents.servlet.restcomm.dao.IncomingPhoneNumbersDao; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.dao.OutgoingCallerIdsDao; -import org.mobicents.servlet.restcomm.dao.RecordingsDao; -import org.mobicents.servlet.restcomm.dao.RegistrationsDao; -import org.mobicents.servlet.restcomm.dao.ShortCodesDao; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.dao.TranscriptionsDao; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisDaoManager implements DaoManager { - private Configuration configuration; - private AccountsDao accountsDao; - private ApplicationsDao applicationsDao; - private AvailablePhoneNumbersDao availablePhoneNumbersDao; - private CallDetailRecordsDao callDetailRecordsDao; - private ClientsDao clientsDao; - private HttpCookiesDao httpCookiesDao; - private IncomingPhoneNumbersDao incomingPhoneNumbersDao; - private NotificationsDao notificationsDao; - private OutgoingCallerIdsDao outgoingCallerIdsDao; - private RegistrationsDao presenceRecordsDao; - private RecordingsDao recordingsDao; - private ShortCodesDao shortCodesDao; - private SmsMessagesDao smsMessagesDao; - private TranscriptionsDao transcriptionsDao; - private GatewaysDao gatewaysDao; - private AnnouncementsDao announcementsDao; - - public MybatisDaoManager() { - super(); - } - - @Override - public void configure(final Configuration configuration) { - this.configuration = configuration; - } - - @Override - public AccountsDao getAccountsDao() { - return accountsDao; - } - - @Override - public ApplicationsDao getApplicationsDao() { - return applicationsDao; - } - - @Override - public AnnouncementsDao getAnnouncementsDao() { - return announcementsDao; - } - - @Override - public AvailablePhoneNumbersDao getAvailablePhoneNumbersDao() { - return availablePhoneNumbersDao; - } - - @Override - public CallDetailRecordsDao getCallDetailRecordsDao() { - return callDetailRecordsDao; - } - - @Override - public ClientsDao getClientsDao() { - return clientsDao; - } - - @Override - public HttpCookiesDao getHttpCookiesDao() { - return httpCookiesDao; - } - - @Override - public IncomingPhoneNumbersDao getIncomingPhoneNumbersDao() { - return incomingPhoneNumbersDao; - } - - @Override - public NotificationsDao getNotificationsDao() { - return notificationsDao; - } - - @Override - public RegistrationsDao getRegistrationsDao() { - return presenceRecordsDao; - } - - @Override - public OutgoingCallerIdsDao getOutgoingCallerIdsDao() { - return outgoingCallerIdsDao; - } - - @Override - public RecordingsDao getRecordingsDao() { - return recordingsDao; - } - - @Override - public ShortCodesDao getShortCodesDao() { - return shortCodesDao; - } - - @Override - public SmsMessagesDao getSmsMessagesDao() { - return smsMessagesDao; - } - - @Override - public TranscriptionsDao getTranscriptionsDao() { - return transcriptionsDao; - } - - @Override - public GatewaysDao getGatewaysDao() { - return gatewaysDao; - } - - @Override - public void shutdown() { - // Nothing to do. - } - - @Override - public void start() throws RuntimeException { - // This must be called before any other MyBatis methods. - org.apache.ibatis.logging.LogFactory.useSlf4jLogging(); - // Load the configuration file. - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final String path = configuration.getString("configuration-file"); - Reader reader = null; - try { - reader = new FileReader(path); - } catch (final FileNotFoundException exception) { - throw new RuntimeException(exception); - } - final Properties properties = new Properties(); - final String dataFiles = configuration.getString("data-files"); - final String sqlFiles = configuration.getString("sql-files"); - properties.setProperty("data", dataFiles); - properties.setProperty("sql", sqlFiles); - final SqlSessionFactory sessions = builder.build(reader, properties); - start(sessions); - } - - public void start(final SqlSessionFactory sessions) { - // Instantiate the DAO objects. - accountsDao = new MybatisAccountsDao(sessions); - applicationsDao = new MybatisApplicationsDao(sessions); - announcementsDao = new MybatisAnnouncementsDao(sessions); - availablePhoneNumbersDao = new MybatisAvailablePhoneNumbersDao(sessions); - callDetailRecordsDao = new MybatisCallDetailRecordsDao(sessions); - clientsDao = new MybatisClientsDao(sessions); - httpCookiesDao = new MybatisHttpCookiesDao(sessions); - incomingPhoneNumbersDao = new MybatisIncomingPhoneNumbersDao(sessions); - notificationsDao = new MybatisNotificationsDao(sessions); - outgoingCallerIdsDao = new MybatisOutgoingCallerIdsDao(sessions); - presenceRecordsDao = new MybatisRegistrationsDao(sessions); - recordingsDao = new MybatisRecordingsDao(sessions); - shortCodesDao = new MybatisShortCodesDao(sessions); - smsMessagesDao = new MybatisSmsMessagesDao(sessions); - transcriptionsDao = new MybatisTranscriptionsDao(sessions); - gatewaysDao = new MybatisGatewaysDao(sessions); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisIncomingPhoneNumbersDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisIncomingPhoneNumbersDao.java deleted file mode 100644 index 361dc77b84..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisIncomingPhoneNumbersDao.java +++ /dev/null @@ -1,233 +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.mobicents.servlet.restcomm.dao.mybatis; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readBoolean; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readDateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readSid; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readString; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readUri; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.writeDateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.writeSid; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.writeUri; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.dao.IncomingPhoneNumbersDao; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumberFilter; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author jean.deruelle@telestax.com - */ -@ThreadSafe -public final class MybatisIncomingPhoneNumbersDao implements IncomingPhoneNumbersDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.IncomingPhoneNumbersDao."; - private final SqlSessionFactory sessions; - - public MybatisIncomingPhoneNumbersDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addIncomingPhoneNumber(final IncomingPhoneNumber incomingPhoneNumber) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addIncomingPhoneNumber", toMap(incomingPhoneNumber)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public IncomingPhoneNumber getIncomingPhoneNumber(final Sid sid) { - return getIncomingPhoneNumber("getIncomingPhoneNumber", sid.toString()); - } - - @Override - public IncomingPhoneNumber getIncomingPhoneNumber(final String phoneNumber) { - return getIncomingPhoneNumber("getIncomingPhoneNumberByValue", phoneNumber); - } - - private IncomingPhoneNumber getIncomingPhoneNumber(final String selector, Object parameter) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(namespace + selector, parameter); - if (result != null) { - return toIncomingPhoneNumber(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getIncomingPhoneNumbers(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getIncomingPhoneNumbers", - accountSid.toString()); - final List incomingPhoneNumbers = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - incomingPhoneNumbers.add(toIncomingPhoneNumber(result)); - } - } - return incomingPhoneNumbers; - } finally { - session.close(); - } - } - - @Override - public List getIncomingPhoneNumbersByFilter(IncomingPhoneNumberFilter filter) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getIncomingPhoneNumbersByFriendlyName", - filter); - final List incomingPhoneNumbers = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - incomingPhoneNumbers.add(toIncomingPhoneNumber(result)); - } - } - return incomingPhoneNumbers; - } finally { - session.close(); - } - } - - @Override - public void removeIncomingPhoneNumber(final Sid sid) { - removeIncomingPhoneNumbers("removeIncomingPhoneNumber", sid); - } - - @Override - public void removeIncomingPhoneNumbers(final Sid accountSid) { - removeIncomingPhoneNumbers("removeIncomingPhoneNumbers", accountSid); - } - - private void removeIncomingPhoneNumbers(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(namespace + selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateIncomingPhoneNumber(final IncomingPhoneNumber incomingPhoneNumber) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateIncomingPhoneNumber", toMap(incomingPhoneNumber)); - session.commit(); - } finally { - session.close(); - } - } - - private IncomingPhoneNumber toIncomingPhoneNumber(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String friendlyName = readString(map.get("friendly_name")); - final Sid accountSid = readSid(map.get("account_sid")); - final String phoneNumber = readString(map.get("phone_number")); - final String apiVersion = readString(map.get("api_version")); - final Boolean hasVoiceCallerIdLookup = readBoolean(map.get("voice_caller_id_lookup")); - final URI voiceUrl = readUri(map.get("voice_url")); - final String voiceMethod = readString(map.get("voice_method")); - final URI voiceFallbackUrl = readUri(map.get("voice_fallback_url")); - final String voiceFallbackMethod = readString(map.get("voice_fallback_method")); - final URI statusCallback = readUri(map.get("status_callback")); - final String statusCallbackMethod = readString(map.get("status_callback_method")); - final Sid voiceApplicationSid = readSid(map.get("voice_application_sid")); - final URI smsUrl = readUri(map.get("sms_url")); - final String smsMethod = readString(map.get("sms_method")); - final URI smsFallbackUrl = readUri(map.get("sms_fallback_url")); - final String smsFallbackMethod = readString(map.get("sms_fallback_method")); - final Sid smsApplicationSid = readSid(map.get("sms_application_sid")); - final URI uri = readUri(map.get("uri")); - final URI ussdUrl = readUri(map.get("ussd_url")); - final String ussdMethod = readString(map.get("ussd_method")); - final URI ussdFallbackUrl = readUri(map.get("ussd_fallback_url")); - final String ussdFallbackMethod = readString(map.get("ussd_fallback_method")); - final Sid ussdApplicationSid = readSid(map.get("ussd_application_sid")); - final Boolean voiceCapable = readBoolean(map.get("voice_capable")); - final Boolean smsCapable = readBoolean(map.get("sms_capable")); - final Boolean mmsCapable = readBoolean(map.get("mms_capable")); - final Boolean faxCapable = readBoolean(map.get("fax_capable")); - return new IncomingPhoneNumber(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, apiVersion, - hasVoiceCallerIdLookup, voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, - statusCallbackMethod, voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, - smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, voiceCapable, smsCapable, mmsCapable, faxCapable); - } - - private Map toMap(final IncomingPhoneNumber incomingPhoneNumber) { - final Map map = new HashMap(); - map.put("sid", writeSid(incomingPhoneNumber.getSid())); - map.put("date_created", writeDateTime(incomingPhoneNumber.getDateCreated())); - map.put("date_updated", writeDateTime(incomingPhoneNumber.getDateUpdated())); - map.put("friendly_name", incomingPhoneNumber.getFriendlyName()); - map.put("account_sid", writeSid(incomingPhoneNumber.getAccountSid())); - map.put("phone_number", incomingPhoneNumber.getPhoneNumber()); - map.put("api_version", incomingPhoneNumber.getApiVersion()); - map.put("voice_caller_id_lookup", incomingPhoneNumber.hasVoiceCallerIdLookup()); - map.put("voice_url", writeUri(incomingPhoneNumber.getVoiceUrl())); - map.put("voice_method", incomingPhoneNumber.getVoiceMethod()); - map.put("voice_fallback_url", writeUri(incomingPhoneNumber.getVoiceFallbackUrl())); - map.put("voice_fallback_method", incomingPhoneNumber.getVoiceFallbackMethod()); - map.put("status_callback", writeUri(incomingPhoneNumber.getStatusCallback())); - map.put("status_callback_method", incomingPhoneNumber.getStatusCallbackMethod()); - map.put("voice_application_sid", writeSid(incomingPhoneNumber.getVoiceApplicationSid())); - map.put("sms_url", writeUri(incomingPhoneNumber.getSmsUrl())); - map.put("sms_method", incomingPhoneNumber.getSmsMethod()); - map.put("sms_fallback_url", writeUri(incomingPhoneNumber.getSmsFallbackUrl())); - map.put("sms_fallback_method", incomingPhoneNumber.getSmsFallbackMethod()); - map.put("sms_application_sid", writeSid(incomingPhoneNumber.getSmsApplicationSid())); - map.put("uri", writeUri(incomingPhoneNumber.getUri())); - map.put("ussd_url", writeUri(incomingPhoneNumber.getUssdUrl())); - map.put("ussd_method", incomingPhoneNumber.getUssdMethod()); - map.put("ussd_fallback_url", writeUri(incomingPhoneNumber.getUssdFallbackUrl())); - map.put("ussd_fallback_method", incomingPhoneNumber.getUssdFallbackMethod()); - map.put("ussd_application_sid", writeSid(incomingPhoneNumber.getUssdApplicationSid())); - map.put("voice_capable", incomingPhoneNumber.isVoiceCapable()); - map.put("sms_capable", incomingPhoneNumber.isSmsCapable()); - map.put("mms_capable", incomingPhoneNumber.isMmsCapable()); - map.put("fax_capable", incomingPhoneNumber.isFaxCapable()); - return map; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRecordingsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRecordingsDao.java deleted file mode 100644 index 5f92cc1403..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRecordingsDao.java +++ /dev/null @@ -1,148 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.RecordingsDao; -import org.mobicents.servlet.restcomm.entities.Recording; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisRecordingsDao implements RecordingsDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.RecordingsDao."; - private final SqlSessionFactory sessions; - - public MybatisRecordingsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addRecording(final Recording recording) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addRecording", toMap(recording)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public Recording getRecording(final Sid sid) { - return getRecording(namespace + "getRecording", sid); - } - - @Override - public Recording getRecordingByCall(final Sid callSid) { - return getRecording(namespace + "getRecordingByCall", callSid); - } - - private Recording getRecording(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(selector, sid.toString()); - if (result != null) { - return toRecording(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getRecordings(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getRecordings", accountSid.toString()); - final List recordings = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - recordings.add(toRecording(result)); - } - } - return recordings; - } finally { - session.close(); - } - } - - @Override - public void removeRecording(final Sid sid) { - removeRecording(namespace + "removeRecording", sid); - } - - @Override - public void removeRecordings(final Sid accountSid) { - removeRecording(namespace + "removeRecordings", accountSid); - } - - private void removeRecording(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - private Map toMap(final Recording recording) { - final Map map = new HashMap(); - map.put("sid", writeSid(recording.getSid())); - map.put("date_created", writeDateTime(recording.getDateCreated())); - map.put("date_updated", writeDateTime(recording.getDateUpdated())); - map.put("account_sid", writeSid(recording.getAccountSid())); - map.put("call_sid", writeSid(recording.getCallSid())); - map.put("duration", recording.getDuration()); - map.put("api_version", recording.getApiVersion()); - map.put("uri", writeUri(recording.getUri())); - return map; - } - - private Recording toRecording(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final Sid accountSid = readSid(map.get("account_sid")); - final Sid callSid = readSid(map.get("call_sid")); - final Double duration = readDouble(map.get("duration")); - final String apiVersion = readString(map.get("api_version")); - final URI uri = readUri(map.get("uri")); - return new Recording(sid, dateCreated, dateUpdated, accountSid, callSid, duration, apiVersion, uri); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRegistrationsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRegistrationsDao.java deleted file mode 100644 index 451cf94b91..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisRegistrationsDao.java +++ /dev/null @@ -1,177 +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.mobicents.servlet.restcomm.dao.mybatis; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readDateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readInteger; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readSid; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.readString; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.writeDateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.writeSid; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.log4j.Logger; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.dao.RegistrationsDao; -import org.mobicents.servlet.restcomm.entities.Registration; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author jean.deruelle@gmail.com (Jean Deruelle) - */ -@ThreadSafe -public final class MybatisRegistrationsDao implements RegistrationsDao { - private static final Logger logger = Logger.getLogger(MybatisRegistrationsDao.class); - - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.RegistrationsDao."; - private final SqlSessionFactory sessions; - - public MybatisRegistrationsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addRegistration(final Registration registration) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addRegistration", toMap(registration)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public Registration getRegistration(String user) { - final SqlSession session = sessions.openSession(); - try { - // https://bitbucket.org/telestax/telscale-restcomm/issue/107/dial-fails-to-call-a-client-registered - // we get all registrations and sort them by latest updated date so that we target the device where the user last - // updated the registration - final List> results = session.selectList(namespace + "getRegistration", user); - final List records = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - records.add(toPresenceRecord(result)); - } - if (records.isEmpty()) { - return null; - } else { - Collections.sort(records); - return records.get(0); - } - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getRegistrations() { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getRegistrations"); - final List records = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - records.add(toPresenceRecord(result)); - } - } - return records; - } finally { - session.close(); - } - } - - @Override - public boolean hasRegistration(final Registration registration) { - final SqlSession session = sessions.openSession(); - try { - final Integer result = (Integer) session.selectOne(namespace + "hasRegistration", toMap(registration)); - return result != null && result > 0; - } finally { - session.close(); - } - } - - @Override - public void removeRegistration(final Registration registration) { - final SqlSession session = sessions.openSession(); - try { - session.delete(namespace + "removeRegistration", toMap(registration)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateRegistration(final Registration registration) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateRegistration", toMap(registration)); - session.commit(); - } finally { - session.close(); - } - } - - private Map toMap(final Registration registration) { - final Map map = new HashMap(); - map.put("sid", writeSid(registration.getSid())); - map.put("date_created", writeDateTime(registration.getDateCreated())); - map.put("date_updated", writeDateTime(registration.getDateUpdated())); - map.put("date_expires", writeDateTime(registration.getDateExpires())); - map.put("address_of_record", registration.getAddressOfRecord()); - map.put("display_name", registration.getDisplayName()); - map.put("user_name", registration.getUserName()); - map.put("location", registration.getLocation()); - map.put("user_agent", registration.getUserAgent()); - map.put("ttl", registration.getTimeToLive()); - return map; - } - - private Registration toPresenceRecord(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final DateTime dateExpires = readDateTime(map.get("date_expires")); - final String addressOfRecord = readString(map.get("address_of_record")); - final String dislplayName = readString(map.get("display_name")); - final String userName = readString(map.get("user_name")); - final String location = readString(map.get("location")); - final String userAgent = readString(map.get("user_agent")); - final Integer timeToLive = readInteger(map.get("ttl")); - return new Registration(sid, dateCreated, dateUpdated, dateExpires, addressOfRecord, dislplayName, userName, userAgent, - timeToLive, location); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisShortCodesDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisShortCodesDao.java deleted file mode 100644 index 639e98a60e..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisShortCodesDao.java +++ /dev/null @@ -1,159 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.ShortCodesDao; -import org.mobicents.servlet.restcomm.entities.ShortCode; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisShortCodesDao implements ShortCodesDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ShortCodesDao."; - private final SqlSessionFactory sessions; - - public MybatisShortCodesDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addShortCode(final ShortCode shortCode) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addShortCode", toMap(shortCode)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public ShortCode getShortCode(final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(namespace + "getShortCode", sid.toString()); - if (result != null) { - return toShortCode(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getShortCodes(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getShortCodes", accountSid.toString()); - final List shortCodes = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - shortCodes.add(toShortCode(result)); - } - } - return shortCodes; - } finally { - session.close(); - } - } - - @Override - public void removeShortCode(final Sid sid) { - removeShortCodes(namespace + "removeShortCode", sid); - } - - @Override - public void removeShortCodes(final Sid accountSid) { - removeShortCodes(namespace + "removeShortCodes", accountSid); - } - - private void removeShortCodes(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateShortCode(final ShortCode shortCode) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateShortCode", toMap(shortCode)); - session.commit(); - } finally { - session.close(); - } - } - - private Map toMap(final ShortCode shortCode) { - final Map map = new HashMap(); - map.put("sid", writeSid(shortCode.getSid())); - map.put("date_created", writeDateTime(shortCode.getDateCreated())); - map.put("date_updated", writeDateTime(shortCode.getDateUpdated())); - map.put("friendly_name", shortCode.getFriendlyName()); - map.put("account_sid", writeSid(shortCode.getAccountSid())); - map.put("short_code", shortCode.getShortCode()); - map.put("api_version", shortCode.getApiVersion()); - map.put("sms_url", writeUri(shortCode.getSmsUrl())); - map.put("sms_method", shortCode.getSmsMethod()); - map.put("sms_fallback_url", writeUri(shortCode.getSmsFallbackUrl())); - map.put("sms_fallback_method", shortCode.getSmsFallbackMethod()); - map.put("uri", writeUri(shortCode.getUri())); - return map; - } - - private ShortCode toShortCode(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String friendlyName = readString(map.get("friendly_name")); - final Sid accountSid = readSid(map.get("account_sid")); - final Integer shortCode = readInteger(map.get("short_code")); - final String apiVersion = readString(map.get("api_version")); - final URI smsUrl = readUri(map.get("sms_url")); - final String smsMethod = readString(map.get("sms_method")); - final URI smsFallbackUrl = readUri(map.get("sms_fallback_url")); - final String smsFallbackMethod = readString(map.get("sms_fallback_method")); - final URI uri = readUri(map.get("uri")); - return new ShortCode(sid, dateCreated, dateUpdated, friendlyName, accountSid, shortCode, apiVersion, smsUrl, smsMethod, - smsFallbackUrl, smsFallbackMethod, uri); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisSmsMessagesDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisSmsMessagesDao.java deleted file mode 100644 index a300071aad..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisSmsMessagesDao.java +++ /dev/null @@ -1,164 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.ArrayList; -import java.util.Currency; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisSmsMessagesDao implements SmsMessagesDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.SmsMessagesDao."; - private final SqlSessionFactory sessions; - - public MybatisSmsMessagesDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addSmsMessage(final SmsMessage smsMessage) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addSmsMessage", toMap(smsMessage)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public SmsMessage getSmsMessage(final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(namespace + "getSmsMessage", sid.toString()); - if (result != null) { - return toSmsMessage(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getSmsMessages(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session.selectList(namespace + "getSmsMessages", accountSid.toString()); - final List smsMessages = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - smsMessages.add(toSmsMessage(result)); - } - } - return smsMessages; - } finally { - session.close(); - } - } - - @Override - public void removeSmsMessage(final Sid sid) { - deleteSmsMessage(namespace + "removeSmsMessage", sid); - } - - @Override - public void removeSmsMessages(final Sid accountSid) { - deleteSmsMessage(namespace + "removeSmsMessages", accountSid); - } - - private void deleteSmsMessage(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - public void updateSmsMessage(final SmsMessage smsMessage) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateSmsMessage", toMap(smsMessage)); - session.commit(); - } finally { - session.close(); - } - } - - private Map toMap(final SmsMessage smsMessage) { - final Map map = new HashMap(); - map.put("sid", writeSid(smsMessage.getSid())); - map.put("date_created", writeDateTime(smsMessage.getDateCreated())); - map.put("date_updated", writeDateTime(smsMessage.getDateUpdated())); - map.put("date_sent", writeDateTime(smsMessage.getDateSent())); - map.put("account_sid", writeSid(smsMessage.getAccountSid())); - map.put("sender", smsMessage.getSender()); - map.put("recipient", smsMessage.getRecipient()); - map.put("body", smsMessage.getBody()); - map.put("status", smsMessage.getStatus().toString()); - map.put("direction", smsMessage.getDirection().toString()); - map.put("price", writeBigDecimal(smsMessage.getPrice())); - map.put("price_unit", writeCurrency(smsMessage.getPriceUnit())); - map.put("api_version", smsMessage.getApiVersion()); - map.put("uri", writeUri(smsMessage.getUri())); - return map; - } - - private SmsMessage toSmsMessage(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final DateTime dateSent = readDateTime(map.get("date_sent")); - final Sid accountSid = readSid(map.get("account_sid")); - final String sender = readString(map.get("sender")); - final String recipient = readString(map.get("recipient")); - final String body = readString(map.get("body")); - final SmsMessage.Status status = SmsMessage.Status.getStatusValue(readString(map.get("status"))); - final SmsMessage.Direction direction = SmsMessage.Direction.getDirectionValue(readString(map.get("direction"))); - final BigDecimal price = readBigDecimal(map.get("price")); - final Currency priceUnit = readCurrency(map.get("price_unit")); - final String apiVersion = readString(map.get("api_version")); - final URI uri = readUri(map.get("uri")); - return new SmsMessage(sid, dateCreated, dateUpdated, dateSent, accountSid, sender, recipient, body, status, direction, - price, priceUnit, apiVersion, uri); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisTranscriptionsDao.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisTranscriptionsDao.java deleted file mode 100644 index d4e417d21b..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisTranscriptionsDao.java +++ /dev/null @@ -1,170 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.ArrayList; -import java.util.Currency; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.TranscriptionsDao; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.Transcription; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class MybatisTranscriptionsDao implements TranscriptionsDao { - private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.TranscriptionsDao."; - private final SqlSessionFactory sessions; - - public MybatisTranscriptionsDao(final SqlSessionFactory sessions) { - super(); - this.sessions = sessions; - } - - @Override - public void addTranscription(final Transcription transcription) { - final SqlSession session = sessions.openSession(); - try { - session.insert(namespace + "addTranscription", toMap(transcription)); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public Transcription getTranscription(final Sid sid) { - return getTranscription(namespace + "getTranscription", sid); - } - - @Override - public Transcription getTranscriptionByRecording(final Sid recordingSid) { - return getTranscription(namespace + "getTranscriptionByRecording", recordingSid); - } - - private Transcription getTranscription(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - final Map result = session.selectOne(selector, sid.toString()); - if (result != null) { - return toTranscription(result); - } else { - return null; - } - } finally { - session.close(); - } - } - - @Override - public List getTranscriptions(final Sid accountSid) { - final SqlSession session = sessions.openSession(); - try { - final List> results = session - .selectList(namespace + "getTranscriptions", accountSid.toString()); - final List transcriptions = new ArrayList(); - if (results != null && !results.isEmpty()) { - for (final Map result : results) { - transcriptions.add(toTranscription(result)); - } - } - return transcriptions; - } finally { - session.close(); - } - } - - @Override - public void removeTranscription(final Sid sid) { - removeTranscriptions(namespace + "removeTranscription", sid); - } - - @Override - public void removeTranscriptions(final Sid accountSid) { - removeTranscriptions(namespace + "removeTranscriptions", accountSid); - } - - private void removeTranscriptions(final String selector, final Sid sid) { - final SqlSession session = sessions.openSession(); - try { - session.delete(selector, sid.toString()); - session.commit(); - } finally { - session.close(); - } - } - - @Override - public void updateTranscription(final Transcription transcription) { - final SqlSession session = sessions.openSession(); - try { - session.update(namespace + "updateTranscription", toMap(transcription)); - session.commit(); - } finally { - session.close(); - } - } - - private Map toMap(final Transcription transcription) { - final Map map = new HashMap(); - map.put("sid", writeSid(transcription.getSid())); - map.put("date_created", writeDateTime(transcription.getDateCreated())); - map.put("date_updated", writeDateTime(transcription.getDateUpdated())); - map.put("account_sid", writeSid(transcription.getAccountSid())); - map.put("status", transcription.getStatus().toString()); - map.put("recording_sid", writeSid(transcription.getRecordingSid())); - map.put("duration", transcription.getDuration()); - map.put("transcription_text", transcription.getTranscriptionText()); - map.put("price", writeBigDecimal(transcription.getPrice())); - map.put("price_unit", writeCurrency(transcription.getPriceUnit())); - map.put("uri", writeUri(transcription.getUri())); - return map; - } - - private Transcription toTranscription(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final Sid accountSid = readSid(map.get("account_sid")); - final String text = readString(map.get("status")); - final Transcription.Status status = Transcription.Status.getStatusValue(text); - final Sid recordingSid = readSid(map.get("recording_sid")); - final Double duration = readDouble(map.get("duration")); - final String transcriptionText = readString(map.get("transcription_text")); - final BigDecimal price = readBigDecimal(map.get("price")); - final Currency priceUnit = readCurrency(map.get("price_unit")); - final URI uri = readUri(map.get("uri")); - return new Transcription(sid, dateCreated, dateUpdated, accountSid, status, recordingSid, duration, transcriptionText, - price, priceUnit, uri); - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Account.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Account.java deleted file mode 100644 index 7f6e0a94b8..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Account.java +++ /dev/null @@ -1,248 +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.mobicents.servlet.restcomm.entities; - -import java.net.URI; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * Represent a user Account - * - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class Account { - private final Sid sid; - private final DateTime dateCreated; - private final DateTime dateUpdated; - private final String emailAddress; - private final String friendlyName; - private final Sid accountSid; - private final Type type; - private final Status status; - private final String authToken; - private final String role; - private final URI uri; - - public Account(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String emailAddress, - final String friendlyName, final Sid accountSid, final Type type, final Status status, final String authToken, - final String role, final URI uri) { - super(); - this.sid = sid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.emailAddress = emailAddress; - this.friendlyName = friendlyName; - this.accountSid = accountSid; - this.type = type; - this.status = status; - this.authToken = authToken; - this.role = role; - this.uri = uri; - } - - public static Builder builder() { - return new Builder(); - } - - public Sid getSid() { - return sid; - } - - public DateTime getDateCreated() { - return dateCreated; - } - - public DateTime getDateUpdated() { - return dateUpdated; - } - - public String getEmailAddress() { - return emailAddress; - } - - public String getFriendlyName() { - return friendlyName; - } - - public Sid getAccountSid() { - return accountSid; - } - - public Type getType() { - return type; - } - - public Status getStatus() { - return status; - } - - public String getAuthToken() { - return authToken; - } - - public String getRole() { - return role; - } - - public URI getUri() { - return uri; - } - - public Account setEmailAddress(final String emailAddress) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public Account setFriendlyName(final String friendlyName) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public Account setType(final Type type) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public Account setStatus(final Status status) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public Account setAuthToken(final String authToken) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public Account setRole(final String role) { - return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, accountSid, type, status, authToken, - role, uri); - } - - public enum Status { - ACTIVE("active"), CLOSED("closed"), SUSPENDED("suspended"), INACTIVE("inactive"), UNINITIALIZED("uninitialized"); - - private final String text; - - private Status(final String text) { - this.text = text; - } - - public static Status getValueOf(final String text) { - Status[] values = values(); - for (final Status value : values) { - if (value.toString().equals(text)) { - return value; - } - } - throw new IllegalArgumentException(text + " is not a valid account status."); - } - - @Override - public String toString() { - return text; - } - }; - - public enum Type { - FULL("Full"), TRIAL("Trial"); - - private final String text; - - private Type(final String text) { - this.text = text; - } - - public static Type getValueOf(final String text) { - Type[] values = values(); - for (final Type value : values) { - if (value.text.equals(text)) { - return value; - } - } - throw new IllegalArgumentException(text + " is not a valid account type."); - } - - @Override - public String toString() { - return text; - } - }; - - public static final class Builder { - private Sid sid; - private String emailAddress; - private String friendlyName; - private Sid accountSid; - private Type type; - private Status status; - private String authToken; - private String role; - private URI uri; - - private Builder() { - super(); - } - - public Account build() { - final DateTime now = DateTime.now(); - return new Account(sid, now, now, emailAddress, friendlyName, accountSid, type, status, authToken, role, uri); - } - - public void setSid(final Sid sid) { - this.sid = sid; - } - - public void setEmailAddress(final String emailAddress) { - this.emailAddress = emailAddress; - } - - public void setFriendlyName(final String friendlyName) { - this.friendlyName = friendlyName; - } - - public void setAccountSid(final Sid accountSid) { - this.accountSid = accountSid; - } - - public void setType(final Type type) { - this.type = type; - } - - public void setStatus(final Status status) { - this.status = status; - } - - public void setAuthToken(final String authToken) { - this.authToken = authToken; - } - - public void setRole(final String role) { - this.role = role; - } - - public void setUri(final URI uri) { - this.uri = uri; - } - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Application.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Application.java deleted file mode 100644 index 90caf0a7a8..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Application.java +++ /dev/null @@ -1,339 +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.mobicents.servlet.restcomm.entities; - -import java.net.URI; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * Represents a RestComm application - * - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ - -@Immutable -public final class Application { - private final Sid sid; - private final DateTime dateCreated; - private final DateTime dateUpdated; - private final String friendlyName; - private final Sid accountSid; - private final String apiVersion; - private final URI voiceUrl; - private final String voiceMethod; - private final URI voiceFallbackUrl; - private final String voiceFallbackMethod; - private final URI statusCallback; - private final String statusCallbackMethod; - private final Boolean hasVoiceCallerIdLookup; - private final URI smsUrl; - private final String smsMethod; - private final URI smsFallbackUrl; - private final String smsFallbackMethod; - private final URI smsStatusCallback; - private final URI uri; - - public Application(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String friendlyName, - final Sid accountSid, final String apiVersion, final URI voiceUrl, final String voiceMethod, - final URI voiceFallbackUrl, final String voiceFallbackMethod, final URI statusCallback, - final String statusCallbackMethod, final Boolean hasVoiceCallerIdLookup, final URI smsUrl, final String smsMethod, - final URI smsFallbackUrl, final String smsFallbackMethod, final URI smsStatusCallback, final URI uri) { - super(); - this.sid = sid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.friendlyName = friendlyName; - this.accountSid = accountSid; - this.apiVersion = apiVersion; - this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; - this.voiceUrl = voiceUrl; - this.voiceMethod = voiceMethod; - this.voiceFallbackUrl = voiceFallbackUrl; - this.voiceFallbackMethod = voiceFallbackMethod; - this.statusCallback = statusCallback; - this.statusCallbackMethod = statusCallbackMethod; - this.smsUrl = smsUrl; - this.smsMethod = smsMethod; - this.smsFallbackUrl = smsFallbackUrl; - this.smsFallbackMethod = smsFallbackMethod; - this.smsStatusCallback = smsStatusCallback; - this.uri = uri; - } - - public static Builder builder() { - return new Builder(); - } - - public Sid getSid() { - return sid; - } - - public DateTime getDateCreated() { - return dateCreated; - } - - public DateTime getDateUpdated() { - return dateUpdated; - } - - public String getFriendlyName() { - return friendlyName; - } - - public Sid getAccountSid() { - return accountSid; - } - - public String getApiVersion() { - return apiVersion; - } - - public Boolean hasVoiceCallerIdLookup() { - return hasVoiceCallerIdLookup; - } - - public URI getVoiceUrl() { - return voiceUrl; - } - - public String getVoiceMethod() { - return voiceMethod; - } - - public URI getVoiceFallbackUrl() { - return voiceFallbackUrl; - } - - public String getVoiceFallbackMethod() { - return voiceFallbackMethod; - } - - public URI getStatusCallback() { - return statusCallback; - } - - public String getStatusCallbackMethod() { - return statusCallbackMethod; - } - - public URI getSmsUrl() { - return smsUrl; - } - - public String getSmsMethod() { - return smsMethod; - } - - public URI getSmsFallbackUrl() { - return smsFallbackUrl; - } - - public String getSmsFallbackMethod() { - return smsFallbackMethod; - } - - public URI getSmsStatusCallback() { - return smsStatusCallback; - } - - public URI getUri() { - return uri; - } - - public Application setFriendlyName(final String friendlyName) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setVoiceUrl(final URI voiceUrl) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setVoiceMethod(final String voiceMethod) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setVoiceFallbackUrl(final URI voiceFallbackUrl) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setVoiceFallbackMethod(final String voiceFallbackMethod) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setStatusCallback(final URI statusCallback) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setStatusCallbackMethod(final String statusCallbackMethod) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setSmsUrl(final URI smsUrl) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setSmsMethod(final String smsMethod) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setSmsFallbackUrl(final URI smsFallbackUrl) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setSmsFallbackMethod(final String smsFallbackMethod) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public Application setSmsStatusCallback(final URI smsStatusCallback) { - return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, smsUrl, - smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public static final class Builder { - private Sid sid; - private String friendlyName; - private Sid accountSid; - private String apiVersion; - private URI voiceUrl; - private String voiceMethod; - private URI voiceFallbackUrl; - private String voiceFallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private Boolean hasVoiceCallerIdLookup; - private URI smsUrl; - private String smsMethod; - private URI smsFallbackUrl; - private String smsFallbackMethod; - private URI smsStatusCallback; - private URI uri; - - private Builder() { - super(); - } - - public Application build() { - final DateTime now = DateTime.now(); - return new Application(sid, now, now, friendlyName, accountSid, apiVersion, voiceUrl, voiceMethod, - voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, hasVoiceCallerIdLookup, - smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, smsStatusCallback, uri); - } - - public void setSid(final Sid sid) { - this.sid = sid; - } - - public void setFriendlyName(final String friendlyName) { - this.friendlyName = friendlyName; - } - - public void setAccountSid(final Sid accountSid) { - this.accountSid = accountSid; - } - - public void setApiVersion(final String apiVersion) { - this.apiVersion = apiVersion; - } - - public void setVoiceUrl(final URI voiceUrl) { - this.voiceUrl = voiceUrl; - } - - public void setVoiceMethod(final String voiceMethod) { - this.voiceMethod = voiceMethod; - } - - public void setVoiceFallbackUrl(final URI voiceFallbackUrl) { - this.voiceFallbackUrl = voiceFallbackUrl; - } - - public void setVoiceFallbackMethod(final String voiceFallbackMethod) { - this.voiceFallbackMethod = voiceFallbackMethod; - } - - public void setStatusCallback(final URI statusCallback) { - this.statusCallback = statusCallback; - } - - public void setStatusCallbackMethod(final String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - public void setHasVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { - this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; - } - - public void setSmsUrl(final URI smsUrl) { - this.smsUrl = smsUrl; - } - - public void setSmsMethod(final String smsMethod) { - this.smsMethod = smsMethod; - } - - public void setSmsFallbackUrl(final URI smsFallbackUrl) { - this.smsFallbackUrl = smsFallbackUrl; - } - - public void setSmsFallbackMethod(final String smsFallbackMethod) { - this.smsFallbackMethod = smsFallbackMethod; - } - - public void setSmsStatusCallback(final URI smsStatusCallback) { - this.smsStatusCallback = smsStatusCallback; - } - - public void setUri(final URI uri) { - this.uri = uri; - } - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecord.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecord.java deleted file mode 100644 index 31cd556015..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecord.java +++ /dev/null @@ -1,347 +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.mobicents.servlet.restcomm.entities; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.Currency; - -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author pavel.slegr@telestax.com - */ -@Immutable -public final class CallDetailRecord { - private final Sid sid; - private final Sid parentCallSid; - private final DateTime dateCreated; - private final DateTime dateUpdated; - private final Sid accountSid; - private final String to; - private final String from; - private final Sid phoneNumberSid; - private final String status; - private final DateTime startTime; - private final DateTime endTime; - private final Integer duration; - private final BigDecimal price; - private final Currency priceUnit; - private final String direction; - private final String answeredBy; - private final String apiVersion; - private final String forwardedFrom; - private final String callerName; - private final URI uri; - - private final String callPath; - - public CallDetailRecord(final Sid sid, final Sid parentCallSid, final DateTime dateCreated, final DateTime dateUpdated, - final Sid accountSid, final String to, final String from, final Sid phoneNumberSid, final String status, - final DateTime startTime, final DateTime endTime, final Integer duration, final BigDecimal price, - final Currency priceUnit, final String direction, final String answeredBy, final String apiVersion, - final String forwardedFrom, final String callerName, final URI uri, final String callPath) { - super(); - this.sid = sid; - this.parentCallSid = parentCallSid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.accountSid = accountSid; - this.to = to; - this.from = from; - this.phoneNumberSid = phoneNumberSid; - this.status = status; - this.startTime = startTime; - this.endTime = endTime; - this.duration = duration; - this.price = price; - this.priceUnit = priceUnit; - this.direction = direction; - this.answeredBy = answeredBy; - this.apiVersion = apiVersion; - this.forwardedFrom = forwardedFrom; - this.callerName = callerName; - this.uri = uri; - this.callPath = callPath; - } - - public static Builder builder() { - return new Builder(); - } - - public Sid getSid() { - return sid; - } - - public Sid getParentCallSid() { - return parentCallSid; - } - - public DateTime getDateCreated() { - return dateCreated; - } - - public DateTime getDateUpdated() { - return dateUpdated; - } - - public Sid getAccountSid() { - return accountSid; - } - - public String getTo() { - return to; - } - - public String getFrom() { - return from; - } - - public Sid getPhoneNumberSid() { - return phoneNumberSid; - } - - public String getStatus() { - return status; - } - - public DateTime getStartTime() { - return startTime; - } - - public DateTime getEndTime() { - return endTime; - } - - public Integer getDuration() { - return duration; - } - - public BigDecimal getPrice() { - return (price == null) ? new BigDecimal("0.0") : price; - } - - public Currency getPriceUnit() { - return (priceUnit == null) ? Currency.getInstance("USD") : priceUnit; - } - - public String getDirection() { - return direction; - } - - public String getAnsweredBy() { - return answeredBy; - } - - public String getApiVersion() { - return apiVersion; - } - - public String getForwardedFrom() { - return forwardedFrom; - } - - public String getCallerName() { - return callerName; - } - - public URI getUri() { - return uri; - } - - public String getCallPath() { - return callPath; - } - - public CallDetailRecord setStatus(final String status) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public CallDetailRecord setStartTime(final DateTime startTime) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public CallDetailRecord setEndTime(final DateTime endTime) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public CallDetailRecord setDuration(final Integer duration) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public CallDetailRecord setPrice(final BigDecimal price) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public CallDetailRecord setAnsweredBy(final String answeredBy) { - return new CallDetailRecord(sid, parentCallSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - @NotThreadSafe - public static final class Builder { - private Sid sid; - private Sid parentCallSid; - private DateTime dateCreated; - private DateTime dateUpdated; - private Sid accountSid; - private String to; - private String from; - private Sid phoneNumberSid; - private String status; - private DateTime startTime; - private DateTime endTime; - private Integer duration; - private BigDecimal price; - private Currency priceUnit; - private String direction; - private String answeredBy; - private String apiVersion; - private String forwardedFrom; - private String callerName; - private URI uri; - - private String callPath; - - private Builder() { - super(); - sid = null; - parentCallSid = null; - dateCreated = null; - dateUpdated = DateTime.now(); - accountSid = null; - to = null; - from = null; - phoneNumberSid = null; - status = null; - startTime = null; - endTime = null; - duration = null; - price = null; - direction = null; - answeredBy = null; - apiVersion = null; - forwardedFrom = null; - callerName = null; - uri = null; - callPath = null; - } - - public CallDetailRecord build() { - return new CallDetailRecord(sid, parentCallSid, dateCreated, dateUpdated, accountSid, to, from, phoneNumberSid, - status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, - callerName, uri, callPath); - } - - public void setSid(final Sid sid) { - this.sid = sid; - } - - public void setParentCallSid(final Sid parentCallSid) { - this.parentCallSid = parentCallSid; - } - - public void setDateCreated(final DateTime dateCreated) { - this.dateCreated = dateCreated; - } - - public void setAccountSid(final Sid accountSid) { - this.accountSid = accountSid; - } - - public void setTo(final String to) { - this.to = to; - } - - public void setFrom(final String from) { - this.from = from; - } - - public void setPhoneNumberSid(final Sid phoneNumberSid) { - this.phoneNumberSid = phoneNumberSid; - } - - public void setStatus(final String status) { - this.status = status; - } - - public void setStartTime(final DateTime startTime) { - this.startTime = startTime; - } - - public void setEndTime(final DateTime endTime) { - this.endTime = endTime; - } - - public void setDuration(final Integer duration) { - this.duration = duration; - } - - public void setPrice(final BigDecimal price) { - this.price = price; - } - - public void setPriceUnit(final Currency priceUnit) { - this.priceUnit = priceUnit; - } - - public void setDirection(final String direction) { - this.direction = direction; - } - - public void setAnsweredBy(final String answeredBy) { - this.answeredBy = answeredBy; - } - - public void setApiVersion(final String apiVersion) { - this.apiVersion = apiVersion; - } - - public void setForwardedFrom(final String forwardedFrom) { - this.forwardedFrom = forwardedFrom; - } - - public void setCallerName(final String callerName) { - this.callerName = callerName; - } - - public void setUri(final URI uri) { - this.uri = uri; - } - - public void setCallPath(final String callPath) { - this.callPath = callPath; - } - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordFilter.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordFilter.java deleted file mode 100644 index df87163641..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.mobicents.servlet.restcomm.entities; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author gvagenas - */ - -@Immutable -public class CallDetailRecordFilter { - - private final String accountSid; - private final String recipient; - private final String sender; - private final String status; - private final String startTime; - private final String parentCallSid; - private final Integer limit; - private final Integer offset; - - public CallDetailRecordFilter(String accountSid, String recipient, String sender, String status, String startTime, - String parentCallSid, Integer limit, Integer offset) { - this.accountSid = accountSid; - - // The LIKE keyword uses '%' to match any (including 0) number of characters, and '_' to match exactly one character - // Add here the '%' keyword so +15126002188 will be the same as 15126002188 and 6002188 - if (recipient != null) - recipient = "%".concat(recipient); - if (sender != null) - sender = "%".concat(sender); - - this.recipient = recipient; - this.sender = sender; - this.status = status; - this.startTime = startTime; - this.parentCallSid = parentCallSid; - this.limit = limit; - this.offset = offset; - } - - public String getSid() { - return accountSid; - } - - public String getRecipient() { - return recipient; - } - - public String getSender() { - return sender; - } - - public String getStatus() { - return status; - } - - public String getStartTime() { - return startTime; - } - - public String getParentCallSid() { - return parentCallSid; - } - - public int getLimit() { - return limit; - } - - public int getOffset() { - return offset; - } - -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumber.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumber.java deleted file mode 100644 index daad30874e..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumber.java +++ /dev/null @@ -1,702 +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.mobicents.servlet.restcomm.entities; - -import java.net.URI; - -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class IncomingPhoneNumber { - private Sid sid; - private DateTime dateCreated; - private DateTime dateUpdated; - private String friendlyName; - private Sid accountSid; - private String phoneNumber; - private String apiVersion; - private Boolean hasVoiceCallerIdLookup; - private URI voiceUrl; - private String voiceMethod; - private URI voiceFallbackUrl; - private String voiceFallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private Sid voiceApplicationSid; - private URI smsUrl; - private String smsMethod; - private URI smsFallbackUrl; - private String smsFallbackMethod; - private Sid smsApplicationSid; - private URI uri; - - private URI ussdUrl; - private String ussdMethod; - private URI ussdFallbackUrl; - private String ussdFallbackMethod; - private Sid ussdApplicationSid; - - // Capabilities - private Boolean voiceCapable; - private Boolean smsCapable; - private Boolean mmsCapable; - private Boolean faxCapable; - - public IncomingPhoneNumber(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, - final String friendlyName, final Sid accountSid, final String phoneNumber, final String apiVersion, - final Boolean hasVoiceCallerIdLookup, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, - final String voiceFallbackMethod, final URI statusCallback, final String statusCallbackMethod, - final Sid voiceApplicationSid, final URI smsUrl, final String smsMethod, final URI smsFallbackUrl, - final String smsFallbackMethod, final Sid smsApplicationSid, final URI uri, final URI ussdUrl, final String ussdMethod, final URI ussdFallbackUrl, - final String ussdFallbackMethod, final Sid ussdApplicationSid) { - this(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, apiVersion, hasVoiceCallerIdLookup, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, - voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, null, null, null, null); - } - - public IncomingPhoneNumber(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, - final String friendlyName, final Sid accountSid, final String phoneNumber, final String apiVersion, - final Boolean hasVoiceCallerIdLookup, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, - final String voiceFallbackMethod, final URI statusCallback, final String statusCallbackMethod, - final Sid voiceApplicationSid, final URI smsUrl, final String smsMethod, final URI smsFallbackUrl, - final String smsFallbackMethod, final Sid smsApplicationSid, final URI uri, final URI ussdUrl, final String ussdMethod, final URI ussdFallbackUrl, - final String ussdFallbackMethod, final Sid ussdApplicationSid, final Boolean voiceCapable, - final Boolean smsCapable, final Boolean mmsCapable, final Boolean faxCapable) { - super(); - this.sid = sid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.friendlyName = friendlyName; - this.accountSid = accountSid; - this.phoneNumber = phoneNumber; - this.apiVersion = apiVersion; - this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; - this.voiceUrl = voiceUrl; - this.voiceMethod = voiceMethod; - this.voiceFallbackUrl = voiceFallbackUrl; - this.voiceFallbackMethod = voiceFallbackMethod; - this.statusCallback = statusCallback; - this.statusCallbackMethod = statusCallbackMethod; - this.voiceApplicationSid = voiceApplicationSid; - this.smsUrl = smsUrl; - this.smsMethod = smsMethod; - this.smsFallbackUrl = smsFallbackUrl; - this.smsFallbackMethod = smsFallbackMethod; - this.smsApplicationSid = smsApplicationSid; - this.uri = uri; - this.ussdUrl = ussdUrl; - this.ussdMethod = ussdMethod; - this.ussdFallbackUrl = ussdFallbackUrl; - this.ussdFallbackMethod = ussdFallbackMethod; - this.ussdApplicationSid = ussdApplicationSid; - this.voiceCapable = voiceCapable; - this.smsCapable = smsCapable; - this.mmsCapable = mmsCapable; - this.faxCapable = faxCapable; - } - - /** - * @return the sid - */ - public Sid getSid() { - return sid; - } - - /** - * @param sid the sid to set - */ - public void setSid(Sid sid) { - this.sid = sid; - } - - /** - * @return the dateCreated - */ - public DateTime getDateCreated() { - return dateCreated; - } - - /** - * @param dateCreated the dateCreated to set - */ - public void setDateCreated(DateTime dateCreated) { - this.dateCreated = dateCreated; - } - - /** - * @return the dateUpdated - */ - public DateTime getDateUpdated() { - return dateUpdated; - } - - /** - * @param dateUpdated the dateUpdated to set - */ - public void setDateUpdated(DateTime dateUpdated) { - this.dateUpdated = dateUpdated; - } - - /** - * @return the friendlyName - */ - public String getFriendlyName() { - return friendlyName; - } - - /** - * @param friendlyName the friendlyName to set - */ - public void setFriendlyName(String friendlyName) { - this.friendlyName = friendlyName; - } - - /** - * @return the accountSid - */ - public Sid getAccountSid() { - return accountSid; - } - - /** - * @param accountSid the accountSid to set - */ - public void setAccountSid(Sid accountSid) { - this.accountSid = accountSid; - } - - /** - * @return the phoneNumber - */ - public String getPhoneNumber() { - return phoneNumber; - } - - /** - * @param phoneNumber the phoneNumber to set - */ - public void setPhoneNumber(String phoneNumber) { - this.phoneNumber = phoneNumber; - } - - /** - * @return the apiVersion - */ - public String getApiVersion() { - return apiVersion; - } - - /** - * @param apiVersion the apiVersion to set - */ - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - /** - * @return the hasVoiceCallerIdLookup - */ - public Boolean hasVoiceCallerIdLookup() { - return hasVoiceCallerIdLookup; - } - - /** - * @param hasVoiceCallerIdLookup the hasVoiceCallerIdLookup to set - */ - public void setHasVoiceCallerIdLookup(Boolean hasVoiceCallerIdLookup) { - this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; - } - - /** - * @return the voiceUrl - */ - public URI getVoiceUrl() { - return voiceUrl; - } - - /** - * @param voiceUrl the voiceUrl to set - */ - public void setVoiceUrl(URI voiceUrl) { - this.voiceUrl = voiceUrl; - } - - /** - * @return the voiceMethod - */ - public String getVoiceMethod() { - return voiceMethod; - } - - /** - * @param voiceMethod the voiceMethod to set - */ - public void setVoiceMethod(String voiceMethod) { - this.voiceMethod = voiceMethod; - } - - /** - * @return the voiceFallbackUrl - */ - public URI getVoiceFallbackUrl() { - return voiceFallbackUrl; - } - - /** - * @param voiceFallbackUrl the voiceFallbackUrl to set - */ - public void setVoiceFallbackUrl(URI voiceFallbackUrl) { - this.voiceFallbackUrl = voiceFallbackUrl; - } - - /** - * @return the voiceFallbackMethod - */ - public String getVoiceFallbackMethod() { - return voiceFallbackMethod; - } - - /** - * @param voiceFallbackMethod the voiceFallbackMethod to set - */ - public void setVoiceFallbackMethod(String voiceFallbackMethod) { - this.voiceFallbackMethod = voiceFallbackMethod; - } - - /** - * @return the statusCallback - */ - public URI getStatusCallback() { - return statusCallback; - } - - /** - * @param statusCallback the statusCallback to set - */ - public void setStatusCallback(URI statusCallback) { - this.statusCallback = statusCallback; - } - - /** - * @return the statusCallbackMethod - */ - public String getStatusCallbackMethod() { - return statusCallbackMethod; - } - - /** - * @param statusCallbackMethod the statusCallbackMethod to set - */ - public void setStatusCallbackMethod(String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - /** - * @return the voiceApplicationSid - */ - public Sid getVoiceApplicationSid() { - return voiceApplicationSid; - } - - /** - * @param voiceApplicationSid the voiceApplicationSid to set - */ - public void setVoiceApplicationSid(Sid voiceApplicationSid) { - this.voiceApplicationSid = voiceApplicationSid; - } - - /** - * @return the smsUrl - */ - public URI getSmsUrl() { - return smsUrl; - } - - /** - * @param smsUrl the smsUrl to set - */ - public void setSmsUrl(URI smsUrl) { - this.smsUrl = smsUrl; - } - - /** - * @return the smsMethod - */ - public String getSmsMethod() { - return smsMethod; - } - - /** - * @param smsMethod the smsMethod to set - */ - public void setSmsMethod(String smsMethod) { - this.smsMethod = smsMethod; - } - - /** - * @return the smsFallbackUrl - */ - public URI getSmsFallbackUrl() { - return smsFallbackUrl; - } - - /** - * @param smsFallbackUrl the smsFallbackUrl to set - */ - public void setSmsFallbackUrl(URI smsFallbackUrl) { - this.smsFallbackUrl = smsFallbackUrl; - } - - /** - * @return the smsFallbackMethod - */ - public String getSmsFallbackMethod() { - return smsFallbackMethod; - } - - /** - * @param smsFallbackMethod the smsFallbackMethod to set - */ - public void setSmsFallbackMethod(String smsFallbackMethod) { - this.smsFallbackMethod = smsFallbackMethod; - } - - /** - * @return the smsApplicationSid - */ - public Sid getSmsApplicationSid() { - return smsApplicationSid; - } - - /** - * @param smsApplicationSid the smsApplicationSid to set - */ - public void setSmsApplicationSid(Sid smsApplicationSid) { - this.smsApplicationSid = smsApplicationSid; - } - - /** - * @return the uri - */ - public URI getUri() { - return uri; - } - - /** - * @param uri the uri to set - */ - public void setUri(URI uri) { - this.uri = uri; - } - - /** - * @return the ussdUrl - */ - public URI getUssdUrl() { - return ussdUrl; - } - - /** - * @param ussdUrl the ussdUrl to set - */ - public void setUssdUrl(URI ussdUrl) { - this.ussdUrl = ussdUrl; - } - - /** - * @return the ussdMethod - */ - public String getUssdMethod() { - return ussdMethod; - } - - /** - * @param ussdMethod the ussdMethod to set - */ - public void setUssdMethod(String ussdMethod) { - this.ussdMethod = ussdMethod; - } - - /** - * @return the ussdFallbackUrl - */ - public URI getUssdFallbackUrl() { - return ussdFallbackUrl; - } - - /** - * @param ussdFallbackUrl the ussdFallbackUrl to set - */ - public void setUssdFallbackUrl(URI ussdFallbackUrl) { - this.ussdFallbackUrl = ussdFallbackUrl; - } - - /** - * @return the ussdFallbackMethod - */ - public String getUssdFallbackMethod() { - return ussdFallbackMethod; - } - - /** - * @param ussdFallbackMethod the ussdFallbackMethod to set - */ - public void setUssdFallbackMethod(String ussdFallbackMethod) { - this.ussdFallbackMethod = ussdFallbackMethod; - } - - /** - * @return the ussdApplicationSid - */ - public Sid getUssdApplicationSid() { - return ussdApplicationSid; - } - - /** - * @param ussdApplicationSid the ussdApplicationSid to set - */ - public void setUssdApplicationSid(Sid ussdApplicationSid) { - this.ussdApplicationSid = ussdApplicationSid; - } - - /** - * @return the voiceCapable - */ - public Boolean isVoiceCapable() { - return voiceCapable; - } - - /** - * @param voiceCapable the voiceCapable to set - */ - public void setVoiceCapable(Boolean voiceCapable) { - this.voiceCapable = voiceCapable; - } - - /** - * @return the smsCapable - */ - public Boolean isSmsCapable() { - return smsCapable; - } - - /** - * @param smsCapable the smsCapable to set - */ - public void setSmsCapable(Boolean smsCapable) { - this.smsCapable = smsCapable; - } - - /** - * @return the mmsCapable - */ - public Boolean isMmsCapable() { - return mmsCapable; - } - - /** - * @param mmsCapable the mmsCapable to set - */ - public void setMmsCapable(Boolean mmsCapable) { - this.mmsCapable = mmsCapable; - } - - /** - * @return the faxCapable - */ - public Boolean isFaxCapable() { - return faxCapable; - } - - /** - * @param faxCapable the faxCapable to set - */ - public void setFaxCapable(Boolean faxCapable) { - this.faxCapable = faxCapable; - } - - public static Builder builder() { - return new Builder(); - } - - @NotThreadSafe - public static final class Builder { - private Sid sid; - private String friendlyName; - private Sid accountSid; - private String phoneNumber; - private String apiVersion; - private Boolean hasVoiceCallerIdLookup; - private URI voiceUrl; - private String voiceMethod; - private URI voiceFallbackUrl; - private String voiceFallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private Sid voiceApplicationSid; - private URI smsUrl; - private String smsMethod; - private URI smsFallbackUrl; - private String smsFallbackMethod; - private Sid smsApplicationSid; - private URI uri; - - private URI ussdUrl; - private String ussdMethod; - private URI ussdFallbackUrl; - private String ussdFallbackMethod; - private Sid ussdApplicationSid; - - // Capabilities - private Boolean voiceCapable; - private Boolean smsCapable; - private Boolean mmsCapable; - private Boolean faxCapable; - - private Builder() { - super(); - } - - public IncomingPhoneNumber build() { - final DateTime now = DateTime.now(); - return new IncomingPhoneNumber(sid, now, now, friendlyName, accountSid, phoneNumber, apiVersion, - hasVoiceCallerIdLookup, voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, - statusCallbackMethod, voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, - smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, voiceCapable, smsCapable, mmsCapable, faxCapable); - } - - public void setSid(final Sid sid) { - this.sid = sid; - } - - public void setFriendlyName(final String friendlyName) { - this.friendlyName = friendlyName; - } - - public void setAccountSid(final Sid accountSid) { - this.accountSid = accountSid; - } - - public void setPhoneNumber(final String phoneNumber) { - this.phoneNumber = phoneNumber; - } - - public void setApiVersion(final String apiVersion) { - this.apiVersion = apiVersion; - } - - public void setHasVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { - this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; - } - - public void setVoiceUrl(final URI voiceUrl) { - this.voiceUrl = voiceUrl; - } - - public void setVoiceMethod(final String voiceMethod) { - this.voiceMethod = voiceMethod; - } - - public void setVoiceFallbackUrl(final URI voiceFallbackUrl) { - this.voiceFallbackUrl = voiceFallbackUrl; - } - - public void setVoiceFallbackMethod(final String voiceFallbackMethod) { - this.voiceFallbackMethod = voiceFallbackMethod; - } - - public void setStatusCallback(final URI statusCallback) { - this.statusCallback = statusCallback; - } - - public void setStatusCallbackMethod(final String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - public void setVoiceApplicationSid(final Sid voiceApplicationSid) { - this.voiceApplicationSid = voiceApplicationSid; - } - - public void setSmsUrl(final URI smsUrl) { - this.smsUrl = smsUrl; - } - - public void setSmsMethod(final String smsMethod) { - this.smsMethod = smsMethod; - } - - public void setSmsFallbackUrl(final URI smsFallbackUrl) { - this.smsFallbackUrl = smsFallbackUrl; - } - - public void setSmsFallbackMethod(final String smsFallbackMethod) { - this.smsFallbackMethod = smsFallbackMethod; - } - - public void setSmsApplicationSid(final Sid smsApplicationSid) { - this.smsApplicationSid = smsApplicationSid; - } - - public void setUri(final URI uri) { - this.uri = uri; - } - - public void setUssdUrl(final URI ussdUrl) { - this.ussdUrl = ussdUrl; - } - - public void setUssdMethod(final String ussdMethod) { - this.ussdMethod = ussdMethod; - } - - public void setUssdFallbackUrl(final URI ussdFallbackUrl) { - this.ussdFallbackUrl = ussdFallbackUrl; - } - - public void setUssdFallbackMethod(final String ussdFallbackMethod) { - this.ussdFallbackMethod = ussdFallbackMethod; - } - - public void setUssdApplicationSid(final Sid ussdApplicationSid) { - this.ussdApplicationSid = ussdApplicationSid; - } - - public void setVoiceCapable(Boolean voiceCapable) { - this.voiceCapable = voiceCapable; - } - - public void setSmsCapable(Boolean smsCapable) { - this.smsCapable = smsCapable; - } - - public void setMmsCapable(Boolean mmsCapable) { - this.mmsCapable = mmsCapable; - } - - public void setFaxCapable(Boolean faxCapable) { - this.faxCapable = faxCapable; - } - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberFilter.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberFilter.java deleted file mode 100644 index bf61a7d562..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberFilter.java +++ /dev/null @@ -1,65 +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.mobicents.servlet.restcomm.entities; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author Jean Deruelle - */ - -@Immutable -public class IncomingPhoneNumberFilter { - - private final String accountSid; - private final String friendlyName; - private final String phoneNumber; - - public IncomingPhoneNumberFilter(String accountSid, String friendlyName, String phoneNumber) { - this.accountSid = accountSid; - this.friendlyName = friendlyName; - // The LIKE keyword uses '%' to match any (including 0) number of characters, and '_' to match exactly one character - // Add here the '%' keyword so +15126002188 will be the same as 15126002188 and 6002188 - if (phoneNumber != null) { - phoneNumber = "%" + phoneNumber + "%"; - phoneNumber = phoneNumber.replaceAll("\\*", "_"); - } - - this.phoneNumber = phoneNumber; - } - - public String getAccountSid() { - return accountSid; - } - - /** - * @return the friendlyName - */ - public String getFriendlyName() { - return friendlyName; - } - - /** - * @return the phoneNumber - */ - public String getPhoneNumber() { - return phoneNumber; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Recording.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Recording.java deleted file mode 100644 index abb4310955..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Recording.java +++ /dev/null @@ -1,134 +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.mobicents.servlet.restcomm.entities; - -import java.net.URI; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class Recording { - private final Sid sid; - private final DateTime dateCreated; - private final DateTime dateUpdated; - private final Sid accountSid; - private final Sid callSid; - private final Double duration; - private final String apiVersion; - private final URI uri; - - public Recording(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final Sid accountSid, - final Sid callSid, final Double duration, final String apiVersion, final URI uri) { - super(); - this.sid = sid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.accountSid = accountSid; - this.callSid = callSid; - this.duration = duration; - this.apiVersion = apiVersion; - this.uri = uri; - } - - public static Builder builder() { - return new Builder(); - } - - public Sid getSid() { - return sid; - } - - public DateTime getDateCreated() { - return dateCreated; - } - - public DateTime getDateUpdated() { - return dateUpdated; - } - - public Sid getAccountSid() { - return accountSid; - } - - public Sid getCallSid() { - return callSid; - } - - public Double getDuration() { - return duration; - } - - public String getApiVersion() { - return apiVersion; - } - - public URI getUri() { - return uri; - } - - @NotThreadSafe - public static final class Builder { - private Sid sid; - private Sid accountSid; - private Sid callSid; - private Double duration; - private String apiVersion; - private URI uri; - - private Builder() { - super(); - } - - public Recording build() { - final DateTime now = DateTime.now(); - return new Recording(sid, now, now, accountSid, callSid, duration, apiVersion, uri); - } - - public void setSid(final Sid sid) { - this.sid = sid; - } - - public void setAccountSid(final Sid accountSid) { - this.accountSid = accountSid; - } - - public void setCallSid(final Sid callSid) { - this.callSid = callSid; - } - - public void setDuration(final double duration) { - this.duration = duration; - } - - public void setApiVersion(final String apiVersion) { - this.apiVersion = apiVersion; - } - - public void setUri(final URI uri) { - this.uri = uri; - } - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Registration.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Registration.java deleted file mode 100644 index 8af7765308..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Registration.java +++ /dev/null @@ -1,120 +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.mobicents.servlet.restcomm.entities; - -import org.joda.time.DateTime; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author jean.deruelle@telestax.com - */ -@Immutable -public final class Registration implements Comparable { - private final Sid sid; - private final DateTime dateCreated; - private final DateTime dateUpdated; - private final DateTime dateExpires; - private final String addressOfRecord; - private final String displayName; - private final String userName; - private final int timeToLive; - private final String location; - private final String userAgent; - - public Registration(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String addressOfRecord, - final String displayName, final String userName, final String userAgent, final int timeToLive, final String location) { - this(sid, dateCreated, dateUpdated, DateTime.now().plusSeconds(timeToLive), addressOfRecord, displayName, userName, - userAgent, timeToLive, location); - } - - public Registration(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final DateTime dateExpires, - final String addressOfRecord, final String displayName, final String userName, final String userAgent, - final int timeToLive, final String location) { - super(); - this.sid = sid; - this.dateCreated = dateCreated; - this.dateUpdated = dateUpdated; - this.dateExpires = dateExpires; - this.addressOfRecord = addressOfRecord; - this.displayName = displayName; - this.userName = userName; - this.location = location; - this.userAgent = userAgent; - this.timeToLive = timeToLive; - } - - public Sid getSid() { - return sid; - } - - public DateTime getDateCreated() { - return dateCreated; - } - - public DateTime getDateUpdated() { - return dateUpdated; - } - - public DateTime getDateExpires() { - return dateExpires; - } - - public String getAddressOfRecord() { - return addressOfRecord; - } - - public String getDisplayName() { - return displayName; - } - - public String getUserName() { - return userName; - } - - public String getLocation() { - return location; - } - - public String getUserAgent() { - return userAgent; - } - - public int getTimeToLive() { - return timeToLive; - } - - public Registration setTimeToLive(final int timeToLive) { - final DateTime now = DateTime.now(); - return new Registration(sid, dateCreated, now, now.plusSeconds(timeToLive), addressOfRecord, displayName, userName, - userAgent, timeToLive, location); - } - - @Override - public int compareTo(Registration registration) { - // use reverse order of comparator to have registrations sorted in descending order - if (this.getDateUpdated().toDate().getTime() > registration.getDateUpdated().toDate().getTime()) - return -1; - else - return 1; - } - -} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Sid.java b/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Sid.java deleted file mode 100644 index 17f5030ee8..0000000000 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Sid.java +++ /dev/null @@ -1,148 +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.mobicents.servlet.restcomm.entities; - -import java.util.UUID; -import java.util.regex.Pattern; - -import org.apache.shiro.crypto.hash.Md5Hash; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class Sid { - public static final Pattern pattern = Pattern.compile("[a-zA-Z0-9]{34}"); - private final String id; - - public enum Type { - ACCOUNT, APPLICATION, ANNOUNCEMENT, CALL, CLIENT, CONFERENCE, GATEWAY, INVALID, NOTIFICATION, PHONE_NUMBER, RECORDING, REGISTRATION, SHORT_CODE, SMS_MESSAGE, TRANSCRIPTION - }; - - private static final Sid INVALID_SID = new Sid("IN00000000000000000000000000000000"); - - public Sid(final String id) throws IllegalArgumentException { - super(); - if (pattern.matcher(id).matches()) { - this.id = id; - } else { - throw new IllegalArgumentException(id + " is an INVALID_SID sid value."); - } - } - - @Override - public boolean equals(Object object) { - if (this == object) { - return true; - } - if (object == null) { - return false; - } - if (getClass() != object.getClass()) { - return false; - } - final Sid other = (Sid) object; - if (!toString().equals(other.toString())) { - return false; - } - return true; - } - - // Issue 108: https://bitbucket.org/telestax/telscale-restcomm/issue/108/account-sid-could-be-a-hash-of-the - public static Sid generate(final Type type, String string) { - String token = new Md5Hash(string).toString(); - switch (type) { - case ACCOUNT: { - return new Sid("AC" + token); - } - default: { - return generate(type); - } - } - } - - public static Sid generate(final Type type) { - final String uuid = UUID.randomUUID().toString().replace("-", ""); - switch (type) { - case ACCOUNT: { - return new Sid("AC" + uuid); - } - case APPLICATION: { - return new Sid("AP" + uuid); - } - case ANNOUNCEMENT: { - return new Sid("AN" + uuid); - } - case CALL: { - return new Sid("CA" + uuid); - } - case CLIENT: { - return new Sid("CL" + uuid); - } - case CONFERENCE: { - return new Sid("CF" + uuid); - } - case GATEWAY: { - return new Sid("GW" + uuid); - } - case INVALID: { - return INVALID_SID; - } - case NOTIFICATION: { - return new Sid("NO" + uuid); - } - case PHONE_NUMBER: { - return new Sid("PN" + uuid); - } - case RECORDING: { - return new Sid("RE" + uuid); - } - case REGISTRATION: { - return new Sid("RG" + uuid); - } - case SHORT_CODE: { - return new Sid("SC" + uuid); - } - case SMS_MESSAGE: { - return new Sid("SM" + uuid); - } - case TRANSCRIPTION: { - return new Sid("TR" + uuid); - } - default: { - return null; - } - } - } - - @Override - public int hashCode() { - final int prime = 5; - int result = 1; - result = prime * result + id.hashCode(); - return result; - } - - @Override - public String toString() { - return id; - } -} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AccountsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AccountsDao.java new file mode 100644 index 0000000000..d7b90aaa75 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AccountsDao.java @@ -0,0 +1,115 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public interface AccountsDao { + void addAccount(Account account); + + Account getAccount(Sid sid); + + Account getAccount(String name); + + /** + * Created to separate the method used to authenticate from + * the method used to obtain an account from the database, using a ordinary + * String parameter. + * Once authentication cannot allow friendly name as username, this + * method can be similar to getAccount(String name), but without + * 'getAccountByFriendlyName' selector. + * @param name + * @return Account to authenticate + */ + Account getAccountToAuthenticate(String name); + + List getChildAccounts(Sid parentSid); + + void removeAccount(Sid sid); + + void updateAccount(Account account); + + /** + * Returns a list of all sub-accounts under a parent account. All nested sub-accounts in + * any level will be returned. Note: + * a) The parent account is not included in the results. + * b) The sub-account order in the returned list follows a top-down logic. So, higher hierarchy account list elements + * always go before lower hierarchy accounts. + * + * It will return an empty array in case the parent has no children or the parent does + * not exist. + * + * @param parentAccountSid + * @return list of account sid or null + */ + List getSubAccountSidsRecursive(Sid parentAccountSid); + + /** + * Returns a list of all the ancestor account SIDs of an Account all the way up to the + * top-level account. It currently works in an iterative way digging through the parentSid property + * until it reaches the top. + * + * The order of the returned list is significant starting with child accounts first and + * ending with the top-level account. + * + * Note, the list does NOT contain the account passed as a parameter. + * + * Examples: + * + * getAccountLineage(toplevelAccount) -> [] + * + * parentAccoun is the direct child of toplevelAccount: + * getAccontLineage(parentAccount) -> [toplevelAccount] + * + * child@company.com is the child of parent@company.com: + * getAccountLineage(childAccount) -> [parent@company.comSID, admininstrator@compahy.comSID] + * + * grantchild@company.com is the child of child@company.com: + * getAccountLineage(grandchildAccount) -> AccountHierarchyDepthCrossed exctption thrown + * + * @param accountSid + * @return + */ + List getAccountLineage(Sid accountSid) throws AccountHierarchyDepthCrossed; + + /** + * Overloaded version of getAccontLineage(Sid) that won't retrieve current account since + * it's already there. Helps having cleaner concepts in the case when the starting child + * account is already loaded. + * + * @param account + * @return + * @throws AccountHierarchyDepthCrossed + */ + List getAccountLineage(Account account) throws AccountHierarchyDepthCrossed; + + /** + * @param sid of organization + * @return + */ + List getAccountsByOrganization(Sid organizationSid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AnnouncementsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AnnouncementsDao.java new file mode 100644 index 0000000000..fd73377af1 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AnnouncementsDao.java @@ -0,0 +1,22 @@ +package org.restcomm.connect.dao; + +import java.util.List; + +import org.restcomm.connect.dao.entities.Announcement; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author George Vagenas + */ + +public interface AnnouncementsDao { + void addAnnouncement(Announcement announcement); + + Announcement getAnnouncement(Sid sid); + + List getAnnouncements(Sid accountSid); + + void removeAnnouncement(Sid sid); + + void removeAnnouncements(Sid accountSid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ApplicationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ApplicationsDao.java similarity index 78% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ApplicationsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ApplicationsDao.java index 0dcb1cdd87..7cfd20806e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ApplicationsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ApplicationsDao.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.Application; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Application; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -32,8 +32,13 @@ public interface ApplicationsDao { Application getApplication(Sid sid); + Application getApplication(String friendlyName); + List getApplications(Sid accountSid); + // this may optionally return related numbers as part of an Application + List getApplicationsWithNumbers(Sid accountSid); + void removeApplication(Sid sid); void removeApplications(Sid accountSid); diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AvailablePhoneNumbersDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AvailablePhoneNumbersDao.java similarity index 92% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AvailablePhoneNumbersDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AvailablePhoneNumbersDao.java index 57abf19fa4..2eb0c3810e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/AvailablePhoneNumbersDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/AvailablePhoneNumbersDao.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumber; +import org.restcomm.connect.dao.entities.AvailablePhoneNumber; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/CallDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/CallDetailRecordsDao.java new file mode 100644 index 0000000000..a679316de0 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/CallDetailRecordsDao.java @@ -0,0 +1,86 @@ +/* + * 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.dao; + +import java.text.ParseException; +import java.util.List; + +import org.joda.time.DateTime; +import org.restcomm.connect.dao.entities.CallDetailRecordFilter; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public interface CallDetailRecordsDao { + void addCallDetailRecord(CallDetailRecord cdr); + + CallDetailRecord getCallDetailRecord(Sid sid); + + List getCallDetailRecordsByAccountSid(Sid accountSid); + + List getCallDetailRecordsByRecipient(String recipient); + + List getCallDetailRecordsBySender(String sender); + + List getCallDetailRecordsByStatus(String status); + + List getCallDetailRecordsByStartTime(DateTime startTime); + + List getCallDetailRecordsByEndTime(DateTime endTime); + + List getCallDetailRecordsByStarTimeAndEndTime(DateTime endTime); + + List getCallDetailRecordsByParentCall(Sid parentCallSid); + + List getCallDetailRecordsByConferenceSid(Sid conferenceSid); + + List getRunningCallDetailRecordsByConferenceSid(Sid conferenceSid); + + Integer getTotalRunningCallDetailRecordsByConferenceSid(Sid conferenceSid); + + List getCallDetailRecordsByInstanceId(Sid instanceId); + + List getInCompleteCallDetailRecordsByInstanceId(Sid instanceId); + + List getCallDetailRecordsByMsId(String msId); + + Double getAverageCallDurationLast24Hours(Sid instanceId) throws ParseException; + + Double getAverageCallDurationLastHour(Sid instanceId) throws ParseException; + + void removeCallDetailRecord(Sid sid); + + void removeCallDetailRecords(Sid accountSid); + + void updateCallDetailRecord(CallDetailRecord cdr); + + void updateInCompleteCallDetailRecordsToCompletedByInstanceId(Sid instanceId); + + // Support for filtering of calls list result, Issue 153 + List getCallDetailRecords(CallDetailRecordFilter filter); + + Integer getTotalCallDetailRecords(CallDetailRecordFilter filter); + + Integer getInProgressCallsByClientName(String client); + + Integer getInProgressCallsByAccountSid(String accountSid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ClientsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ClientsDao.java similarity index 84% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ClientsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ClientsDao.java index 8ea82edcc0..b245d32ba2 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ClientsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ClientsDao.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.Client; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -32,10 +32,12 @@ public interface ClientsDao { Client getClient(Sid sid); - Client getClient(String user); + Client getClient(String user, Sid organizationSid); List getClients(Sid accountSid); + List getAllClients(); + void removeClient(Sid sid); void removeClients(Sid accountSid); diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ConferenceDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ConferenceDetailRecordsDao.java new file mode 100644 index 0000000000..77e99f9ad7 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ConferenceDetailRecordsDao.java @@ -0,0 +1,78 @@ +/* + * 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.dao; + +import java.util.List; +import java.util.Map; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.dao.entities.ConferenceDetailRecordFilter; +import org.restcomm.connect.dao.entities.ConferenceRecordCountFilter; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +public interface ConferenceDetailRecordsDao { + ConferenceDetailRecord getConferenceDetailRecord(Sid sid); + + List getConferenceDetailRecords(Sid accountSid); + + List getConferenceDetailRecordsByStatus(String status); + + List getConferenceDetailRecords(ConferenceDetailRecordFilter filter); + + List getConferenceDetailRecordsByDateCreated(DateTime dateCreated); + + List getConferenceDetailRecordsByDateUpdated(DateTime dateUpdated); + + Integer getTotalConferenceDetailRecords(ConferenceDetailRecordFilter filter); + + Integer countByFilter(ConferenceRecordCountFilter filter); + + int addConferenceDetailRecord(ConferenceDetailRecord cdr); + + void removeConferenceDetailRecord(Sid sid); + + void removeConferenceDetailRecords(Sid accountSid); + + void updateConferenceDetailRecordStatus(ConferenceDetailRecord cdr); + + void updateConferenceDetailRecordMasterEndpointID(ConferenceDetailRecord cdr); + + void updateMasterPresent(ConferenceDetailRecord cdr); + + void updateConferenceDetailRecordMasterBridgeEndpointID(ConferenceDetailRecord cdr); + + void updateModeratorPresent(ConferenceDetailRecord cdr); + + /** + * @param params + * {sid, mode=IN, jdbcType=VARCHAR} + * {status, mode=IN, jdbcType=VARCHAR} + * {slaveMsId, mode=IN, jdbcType=VARCHAR} + * {dateUpdated, mode=IN, jdbcType=TIMESTAMP} + * {amIMaster, mode=IN, jdbcType=BOOLEAN} + * {completed, mode=OUT, jdbcType=BOOLEAN} + * @return true/false depending on if calling agent was able to complete the conference or not. + */ + boolean completeConferenceDetailRecord(Map params); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoManager.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoManager.java new file mode 100644 index 0000000000..5e6d77c3bb --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoManager.java @@ -0,0 +1,81 @@ +/* + * 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.dao; + +import org.restcomm.connect.commons.Configurable; +import org.restcomm.connect.commons.LifeCycle; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public interface DaoManager extends Configurable, LifeCycle { + AccountsDao getAccountsDao(); + + ApplicationsDao getApplicationsDao(); + + AnnouncementsDao getAnnouncementsDao(); + + AvailablePhoneNumbersDao getAvailablePhoneNumbersDao(); + + CallDetailRecordsDao getCallDetailRecordsDao(); + + ConferenceDetailRecordsDao getConferenceDetailRecordsDao(); + + ClientsDao getClientsDao(); + + HttpCookiesDao getHttpCookiesDao(); + + IncomingPhoneNumbersDao getIncomingPhoneNumbersDao(); + + NotificationsDao getNotificationsDao(); + + OutgoingCallerIdsDao getOutgoingCallerIdsDao(); + + RegistrationsDao getRegistrationsDao(); + + RecordingsDao getRecordingsDao(); + + ShortCodesDao getShortCodesDao(); + + SmsMessagesDao getSmsMessagesDao(); + + UsageDao getUsageDao(); + + TranscriptionsDao getTranscriptionsDao(); + + GatewaysDao getGatewaysDao(); + + InstanceIdDao getInstanceIdDao(); + + MediaServersDao getMediaServersDao(); + + MediaResourceBrokerDao getMediaResourceBrokerDao(); + + ExtensionsConfigurationDao getExtensionsConfigurationDao(); + + GeolocationDao getGeolocationDao(); + + ProfileAssociationsDao getProfileAssociationsDao(); + + OrganizationsDao getOrganizationsDao(); + + ProfilesDao getProfilesDao(); + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoUtils.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoUtils.java new file mode 100644 index 0000000000..865f102b3e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/DaoUtils.java @@ -0,0 +1,233 @@ +/* + * 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.dao; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.util.Currency; +import java.util.Date; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.dao.entities.Organization; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class DaoUtils { + private DaoUtils() { + super(); + } + + public static Account.Status readAccountStatus(final Object object) { + if (object != null) { + return Account.Status.getValueOf((String) object); + } else { + return null; + } + } + + public static Organization.Status readOrganizationStatus(final Object object) { + if (object != null) { + return Organization.Status.getValueOf((String) object); + } else { + return null; + } + } + + public static Account.Type readAccountType(final Object object) { + if (object != null) { + return Account.Type.getValueOf((String) object); + } else { + return null; + } + } + + public static BigDecimal readBigDecimal(final Object object) { + if (object != null) { + return new BigDecimal((String) object); + } else { + return null; + } + } + + public static Boolean readBoolean(final Object object) { + if (object != null) { + return (Boolean) object; + } else { + return null; + } + } + + public static DateTime readDateTime(final Object object) { + if (object != null) { + return new DateTime((Date) object); + } else { + return null; + } + } + + public static Double readDouble(final Object object) { + if (object != null) { + return (Double) object; + } else { + return null; + } + } + + public static Integer readInteger(final Object object) { + if (object != null) { + return (Integer) object; + } else { + return null; + } + } + + public static BigInteger readBigInteger(final Object object) { + if (object != null) { + return (BigInteger) object; + } else { + return null; + } + } + + public static Long readLong(final Object object) { + if (object != null) { + return (Long) object; + } else { + return null; + } + } + + public static Sid readSid(final Object object) { + if (object != null) { + return new Sid((String) object); + } else { + return null; + } + } + + public static String readString(final Object object) { + if (object != null) { + return (String) object; + } else { + return null; + } + } + + public static URI readUri(final Object object) { + if (object != null) { + return URI.create((String) object); + } else { + return null; + } + } + + public static Currency readCurrency(final Object object) { + if (object != null) { + return Currency.getInstance((String) object); + } else { + return null; + } + } + + public static Application.Kind readApplicationKind(final Object object) { + if (object != null) { + return Application.Kind.getValueOf((String) object); + } else { + return null; + } + } + + public static Geolocation.GeolocationType readGeolocationType(final Object object) { + if (object != null) { + return Geolocation.GeolocationType.getValueOf((String) object); + } else { + return null; + } + } + + public static String writeAccountStatus(final Account.Status status) { + return status.toString(); + } + + public static String writeOrganizationStatus(final Organization.Status status) { + return status.toString(); + } + + public static String writeAccountType(final Account.Type type) { + return type.toString(); + } + + public static String writeBigDecimal(final BigDecimal bigDecimal) { + if (bigDecimal != null) { + return bigDecimal.toString(); + } else { + return null; + } + } + + public static Date writeDateTime(final DateTime dateTime) { + if (dateTime != null) { + return dateTime.toDate(); + } else { + return null; + } + } + + public static String writeSid(final Sid sid) { + if (sid != null) { + return sid.toString(); + } else { + return null; + } + } + + public static String writeUri(final URI uri) { + if (uri != null) { + return uri.toString(); + } else { + return null; + } + } + + public static String writeCurrency(final Currency currency) { + if (currency != null) { + return currency.getCurrencyCode(); + } else { + return null; + } + } + + public static String writeApplicationKind(Application.Kind kind) { + if (kind != null) { + return kind.toString(); + } else { + return null; + } + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java new file mode 100644 index 0000000000..a66a4484dc --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java @@ -0,0 +1,129 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.dao; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.api.ExtensionConfiguration; + +import java.util.List; + +/** + * Created by gvagenas on 11/10/2016. + */ +public interface ExtensionsConfigurationDao { + /** + * Add a new ExtensionConfiguration + * @param extensionConfiguration + */ + void addConfiguration(ExtensionConfiguration extensionConfiguration) throws ConfigurationException; + + /** + * Update an existing ExtensionConfiguration + * @param extensionConfiguration + */ + void updateConfiguration(ExtensionConfiguration extensionConfiguration) throws ConfigurationException; + + /** + * Get extension configuration by extension name + * @param extensionName + * @return ExtensionConfiguration + */ + ExtensionConfiguration getConfigurationByName(String extensionName); + + /** + * Get extension configuration by Sid + * @param extensionSid + * @return ExtensionConfiguration + */ + ExtensionConfiguration getConfigurationBySid(Sid extensionSid); + + /** + * Get all extension configuration + * @return List + */ + List getAllConfiguration(); + + /** + * Delete extension configuration by extension name + * @param extensionName + */ + void deleteConfigurationByName(String extensionName); + + /** + * Delete extension configuration by Sid + * @param extensionSid + */ + void deleteConfigurationBySid(Sid extensionSid); + + /** + * Check if there is a newer version of the configuration in the DB using extension name + * @param extensionName + * @param dateTime + * @return + */ + boolean isLatestVersionByName(String extensionName, DateTime dateTime); + + /** + * Check if there is a newer version of the configuration in the DB using extension sid + * @param extensionSid + * @param dateTime + * @return + */ + boolean isLatestVersionBySid(Sid extensionSid, DateTime dateTime); + + + /** + * Validate extension configuration based on the type of the configuration data + * @param extensionConfiguration + * @return + */ + boolean validate(ExtensionConfiguration extensionConfiguration); + + /** + * Get account specific ExtensionConfiguration + * @param accountSid + * @param extensionSid + * @return ExtensionConfiguration + */ + ExtensionConfiguration getAccountExtensionConfiguration(String accountSid, String extensionSid); + + /** + * Add a new account specific ExtensionConfiguration + * @param extensionConfiguration + * @param accountSid + */ + void addAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException; + + /** + * Update an existing account specific ExtensionConfiguration + * @param extensionConfiguration + * @param accountSid + */ + void updateAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException; + + /** + * Delete account specific ExtensionConfiguration + * @param accountSid + * @param extensionSid + */ + void deleteAccountExtensionConfiguration(String accountSid, String extensionSid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/GatewaysDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GatewaysDao.java similarity index 88% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/GatewaysDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GatewaysDao.java index efa2040053..cfcbad322c 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/GatewaysDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GatewaysDao.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.Gateway; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GeolocationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GeolocationDao.java new file mode 100644 index 0000000000..ccc1b9942e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/GeolocationDao.java @@ -0,0 +1,46 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao; + +import java.util.List; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.commons.dao.Sid;; + +/** + * @author Fernando Mendioroz (fernando.mendioroz@telestax.com) + * + */ +public interface GeolocationDao { + + void addGeolocation(Geolocation gl); + + Geolocation getGeolocation(Sid sid); + + List getGeolocations(Sid sid); + + void removeGeolocation(Sid sid); + + void removeGeolocations(Sid sid); + + void updateGeolocation(Geolocation gl); +} + diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/HttpCookiesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/HttpCookiesDao.java similarity index 92% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/HttpCookiesDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/HttpCookiesDao.java index 20ec67eb70..7286f890c6 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/HttpCookiesDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/HttpCookiesDao.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; import org.apache.http.cookie.Cookie; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/IncomingPhoneNumbersDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/IncomingPhoneNumbersDao.java similarity index 76% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/IncomingPhoneNumbersDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/IncomingPhoneNumbersDao.java index 00abaa1d86..140f58a9bf 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/IncomingPhoneNumbersDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/IncomingPhoneNumbersDao.java @@ -17,17 +17,18 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumberFilter; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author jean.deruelle@telestax.com + * @author maria.farooq@telestax.com (Maria Farooq) */ public interface IncomingPhoneNumbersDao { void addIncomingPhoneNumber(IncomingPhoneNumber incomingPhoneNumber); @@ -38,11 +39,13 @@ public interface IncomingPhoneNumbersDao { List getIncomingPhoneNumbersByFilter(IncomingPhoneNumberFilter incomingPhoneNumberFilter); - IncomingPhoneNumber getIncomingPhoneNumber(String phoneNumber); - void removeIncomingPhoneNumber(Sid sid); void removeIncomingPhoneNumbers(Sid accountSid); void updateIncomingPhoneNumber(IncomingPhoneNumber incomingPhoneNumber); + + List getIncomingPhoneNumbersRegex(IncomingPhoneNumberFilter incomingPhoneNumberFilter); + + Integer getTotalIncomingPhoneNumbers(IncomingPhoneNumberFilter filter); } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/InstanceIdDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/InstanceIdDao.java new file mode 100644 index 0000000000..59e0de9787 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/InstanceIdDao.java @@ -0,0 +1,34 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.dao; + +import org.restcomm.connect.dao.entities.InstanceId; + +/** + * @author gvagenas + * + */ +public interface InstanceIdDao { + InstanceId getInstanceId(); + InstanceId getInstanceIdByHost(String host); + void addInstancecId(InstanceId instanceId); + void updateInstanceId(InstanceId instanceId); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaResourceBrokerDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaResourceBrokerDao.java new file mode 100644 index 0000000000..5ce634d199 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaResourceBrokerDao.java @@ -0,0 +1,42 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.MediaResourceBrokerEntity; +import org.restcomm.connect.dao.entities.MediaResourceBrokerEntityFilter; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public interface MediaResourceBrokerDao { + + void addMediaResourceBrokerEntity(MediaResourceBrokerEntity ms); + + List getMediaResourceBrokerEntities(); + + List getConnectedSlaveEntitiesByConfSid(Sid conferenceSid); + + void removeMediaResourceBrokerEntity(MediaResourceBrokerEntityFilter filter); + + void updateMediaResource(MediaResourceBrokerEntity ms); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaServersDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaServersDao.java new file mode 100644 index 0000000000..49c3ba45e3 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/MediaServersDao.java @@ -0,0 +1,42 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.dao.entities.MediaServerEntity; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public interface MediaServersDao { + + void addMediaServer(MediaServerEntity ms); + + List getMediaServerEntityByIP(String msIPAddres); + + List getMediaServers(); + + MediaServerEntity getMediaServer(String msId); + + void removeMediaServerEntity(String msId); + + void updateMediaServer(MediaServerEntity ms); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/NotificationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/NotificationsDao.java similarity index 78% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/NotificationsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/NotificationsDao.java index 098e372569..3a4ed9f4d9 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/NotificationsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/NotificationsDao.java @@ -17,14 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.NotificationFilter; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -47,4 +48,8 @@ public interface NotificationsDao { void removeNotifications(Sid accountSid); void removeNotificationsByCall(Sid callSid); + + // Support for filtering of notification list result, Issue 1395 + Integer getTotalNotification(NotificationFilter filter); + List getNotifications(NotificationFilter filter); } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OrganizationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OrganizationsDao.java new file mode 100644 index 0000000000..0bb2627b89 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OrganizationsDao.java @@ -0,0 +1,68 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Organization; + +/** + * @author Maria Farooq + */ +public interface OrganizationsDao { + /** + * add new Organization + * + * @param organization + */ + void addOrganization(final Organization organization); + /** + * getOrganization by sid + * @param sid + * @return Organization entity + */ + Organization getOrganization(final Sid sid); + + /** + * getOrganizationByDomainName + * @param domainName + * @return Organization entity + */ + Organization getOrganizationByDomainName(final String domainName); + + /** + * getOrganizationByStatus + * @param status + * @return + */ + List getOrganizationsByStatus(final Organization.Status status); + + /** + * @return + */ + List getAllOrganizations(); + + /** + * updateOrganization + * @param organization + */ + void updateOrganization(final Organization organization); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/OutgoingCallerIdsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OutgoingCallerIdsDao.java similarity index 88% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/OutgoingCallerIdsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OutgoingCallerIdsDao.java index b016590565..763ac5cd38 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/OutgoingCallerIdsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/OutgoingCallerIdsDao.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerId; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.entities.OutgoingCallerId; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfileAssociationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfileAssociationsDao.java new file mode 100644 index 0000000000..06c05e384b --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfileAssociationsDao.java @@ -0,0 +1,83 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.dao.entities.ProfileAssociation; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public interface ProfileAssociationsDao { + + /** + * @param targetSid + * @return ProfileAssociation as per provided target sid + */ + ProfileAssociation getProfileAssociationByTargetSid(String targetSid); + + /** + * @param profileSid + * @return List of all ProfileAssociation with a give profile sid + */ + List getProfileAssociationsByProfileSid(String profileSid); + + /** + * @param profileAssociation + * @return + */ + int addProfileAssociation(ProfileAssociation profileAssociation); + + /** + * update ProfileAssociation Of TargetSid to new Profile Sid. + * @param profileAssociation + */ + void updateProfileAssociationOfTargetSid(ProfileAssociation profileAssociation); + + /** + * update Associated Profile Of All Such ProfileSid + * @param oldProfileSid + * @param newProfileSid + */ + void updateAssociatedProfileOfAllSuchProfileSid(String oldProfileSid, String newProfileSid); + + /** + * will delete all associations of given profile sid + * @param profileSid + */ + void deleteProfileAssociationByProfileSid(String profileSid); + + /** + * will delete all associations of given target sid + * @param targetSid + * @return number of associations removed + * + */ + int deleteProfileAssociationByTargetSid(String targetSid); + + /** + * will delete all associations of given target sid + * @param targetSid + * @return number of associations removed + * + */ + int deleteProfileAssociationByTargetSid(String targetSid, String profileSid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfilesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfilesDao.java new file mode 100644 index 0000000000..fdaf355e9a --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ProfilesDao.java @@ -0,0 +1,60 @@ +/* + * 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.dao; + +import java.sql.SQLException; +import java.util.List; + +import org.restcomm.connect.dao.entities.Profile; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public interface ProfilesDao { + + /** + * @param sid + * @return a single profile as per provided profile sid + * @throws SQLException + */ + Profile getProfile(String sid) throws SQLException; + + /** + * @return List of all profiles in the system + * @throws SQLException + */ + List getAllProfiles() throws SQLException; + + /** + * @param profile + * @return + */ + int addProfile(Profile profile); + + /** + * @param profile + */ + void updateProfile(Profile profile); + + /** + * @param profile + */ + void deleteProfile(String sid); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RecordingsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RecordingsDao.java new file mode 100644 index 0000000000..0a897ede09 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RecordingsDao.java @@ -0,0 +1,56 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.dao.entities.MediaAttributes; +import org.restcomm.connect.commons.amazonS3.S3AccessTool; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.RecordingFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public interface RecordingsDao { + void addRecording(Recording recording, MediaAttributes.MediaType mediaType); + + Recording getRecording(Sid sid); + + // otsakir: is this really needed? + Recording getRecordingByCall(Sid callSid); + + List getRecordingsByCall(Sid callSid); + + List getRecordings(Sid accountSid); + + void removeRecording(Sid sid); + + void removeRecordings(Sid accountSid); + + // Support for filtering of recording list result, Issue 1395 + Integer getTotalRecording(RecordingFilter filter); + List getRecordings(RecordingFilter filter); + + void updateRecording(Recording recording); + + S3AccessTool getS3AccessTool(); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RegistrationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RegistrationsDao.java new file mode 100644 index 0000000000..c67df6b9f4 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/RegistrationsDao.java @@ -0,0 +1,51 @@ +/* + * 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.dao; + +import java.util.List; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Registration; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public interface RegistrationsDao { + void addRegistration(Registration registration); + + Registration getRegistration(String user, Sid organizationSid); + + List getRegistrationsByLocation(String user, String location); + + Registration getRegistrationByInstanceId(String User, String instanceId); + + List getRegistrationsByInstanceId(String instanceId); + + List getRegistrations(String user, Sid organizationSid); + + List getRegistrations(); + + boolean hasRegistration(Registration registration); + + void removeRegistration(Registration registration); + + void updateRegistration(Registration registration); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ShortCodesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ShortCodesDao.java similarity index 88% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ShortCodesDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ShortCodesDao.java index 4cfee32d4d..3b288ea082 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/ShortCodesDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ShortCodesDao.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.ShortCode; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.entities.ShortCode; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/SmsMessagesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/SmsMessagesDao.java new file mode 100644 index 0000000000..646699a098 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/SmsMessagesDao.java @@ -0,0 +1,50 @@ +/* + * 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.dao; + +import java.text.ParseException; +import java.util.List; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessageFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public interface SmsMessagesDao { + void addSmsMessage(SmsMessage smsMessage); + + SmsMessage getSmsMessage(Sid sid); + + List getSmsMessages(final Sid accountSid); + + void removeSmsMessage(Sid sid); + + void removeSmsMessages(Sid accountSid); + + void updateSmsMessage(SmsMessage smsMessage); + + int getSmsMessagesPerAccountLastPerMinute(String accountSid) throws ParseException; + + // Support for filtering of message list result, Issue 1395 + Integer getTotalSmsMessage(SmsMessageFilter filter); + List getSmsMessages(SmsMessageFilter filter); +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/TranscriptionsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/TranscriptionsDao.java similarity index 76% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/TranscriptionsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/TranscriptionsDao.java index 0039698d3f..9fe9554d8c 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/TranscriptionsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/TranscriptionsDao.java @@ -17,12 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao; +package org.restcomm.connect.dao; import java.util.List; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.Transcription; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Transcription; +import org.restcomm.connect.dao.entities.TranscriptionFilter; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -41,4 +42,8 @@ public interface TranscriptionsDao { void removeTranscriptions(Sid accountSid); void updateTranscription(Transcription transcription); + + // Support for filtering of notification list result, Issue 1395 + Integer getTotalTranscription(TranscriptionFilter filter); + List getTranscriptions(TranscriptionFilter filter); } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/UsageDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/UsageDao.java new file mode 100644 index 0000000000..0b393ef59f --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/UsageDao.java @@ -0,0 +1,60 @@ +/* + * 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.dao; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Usage; + +import java.util.List; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +public interface UsageDao { + List getUsage(final Sid accountSid); + + List getUsageDaily(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageMonthly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageYearly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageAllTime(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsage(final Sid accountSid, String uri); + + List getUsageDaily(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri); + + List getUsageMonthly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri); + + List getUsageYearly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri); + + List getUsageAllTime(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri); + /* + List getUsageToday(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageYesterday(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageThisMonth(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + + List getUsageLastMonth(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate); + */ +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/common/OrganizationUtil.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/common/OrganizationUtil.java new file mode 100644 index 0000000000..04b271171d --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/common/OrganizationUtil.java @@ -0,0 +1,63 @@ +/* + * 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.dao.common; + + +import javax.servlet.sip.SipURI; + +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Organization; + + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public class OrganizationUtil { + + private static Logger logger = Logger.getLogger(OrganizationUtil.class); + + /** + * getOrganizationSidBySipURIHost + * + * @param sipURI + * @return Sid of Organization + */ + public static Sid getOrganizationSidBySipURIHost(DaoManager storage, final SipURI sipURI) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("getOrganizationSidBySipURIHost sipURI = %s", sipURI)); + } + final String organizationDomainName = sipURI.getHost(); + Organization organization = storage.getOrganizationsDao().getOrganizationByDomainName(organizationDomainName); + return organization == null ? null : organization.getSid(); + } + + /** + * getOrganizationSidByAccountSid + * + * @param accountSid + * @return Sid of Organization + */ + public static Sid getOrganizationSidByAccountSid(DaoManager storage, final Sid accountSid) { + return storage.getAccountsDao().getAccount(accountSid).getOrganizationSid(); + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Account.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Account.java new file mode 100644 index 0000000000..8336fb8a4e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Account.java @@ -0,0 +1,279 @@ +/* + * 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.dao.entities; + +import java.net.URI; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; + +/** + * Represent a user Account + * + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@Immutable +public final class Account { + private final Sid sid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final String emailAddress; + private final String friendlyName; + private final Sid parentSid; + private final Type type; + private final Status status; + private final String authToken; + private final String role; + private final URI uri; + private final Sid organizationSid; + + public Account(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String emailAddress, + final String friendlyName, final Sid parentSid, final Type type, final Status status, final String authToken, + final String role, final URI uri, final Sid organizationSid) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.emailAddress = emailAddress; + this.friendlyName = friendlyName; + this.parentSid = parentSid; + this.type = type; + this.status = status; + this.authToken = authToken; + this.role = role; + this.uri = uri; + this.organizationSid = organizationSid; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public String getEmailAddress() { + return emailAddress; + } + + public String getFriendlyName() { + return friendlyName; + } + + public Sid getParentSid() { + return parentSid; + } + + public Type getType() { + return type; + } + + public Status getStatus() { + return status; + } + + public String getAuthToken() { + return authToken; + } + + public String getRole() { + return role; + } + + public URI getUri() { + return uri; + } + + public Sid getOrganizationSid() { + return organizationSid; + } + + public Account setEmailAddress(final String emailAddress) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setFriendlyName(final String friendlyName) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setType(final Type type) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setStatus(final Status status) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setAuthToken(final String authToken) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setRole(final String role) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public Account setOrganizationSid(final Sid organizationSid) { + return new Account(sid, dateCreated, DateTime.now(), emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + public enum Status { + ACTIVE("active"), CLOSED("closed"), SUSPENDED("suspended"), INACTIVE("inactive"), UNINITIALIZED("uninitialized"); + + private final String text; + + private Status(final String text) { + this.text = text; + } + + public static Status getValueOf(final String text) { + Status[] values = values(); + for (final Status value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid account status."); + } + + @Override + public String toString() { + return text; + } + }; + + public enum Type { + FULL("Full"), TRIAL("Trial"); + + private final String text; + + private Type(final String text) { + this.text = text; + } + + public static Type getValueOf(final String text) { + Type[] values = values(); + for (final Type value : values) { + if (value.text.equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid account type."); + } + + @Override + public String toString() { + return text; + } + }; + + public static final class Builder { + private Sid sid; + private String emailAddress; + private String friendlyName; + private Sid parentSid; + private Type type; + private Status status; + private String authToken; + private String role; + private URI uri; + private Sid organizationSid; + + private Builder() { + super(); + } + + public Builder copy(Account account) { + sid = account.getSid(); + parentSid = account.getParentSid(); + organizationSid = account.getOrganizationSid(); + type = account.getType(); + uri = account.getUri(); + authToken = account.getAuthToken(); + emailAddress = account.getEmailAddress(); + friendlyName = account.getFriendlyName(); + role = account.getRole(); + status = account.getStatus(); + return this; + } + + public Account build() { + final DateTime now = DateTime.now(); + return new Account(sid, now, now, emailAddress, friendlyName, parentSid, type, status, authToken, role, uri, organizationSid); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setEmailAddress(final String emailAddress) { + this.emailAddress = emailAddress; + } + + public void setFriendlyName(final String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setParentSid(final Sid parentSid) { + this.parentSid = parentSid; + } + + public void setOrganizationSid(final Sid organizationSid) { + this.organizationSid = organizationSid; + } + + public void setType(final Type type) { + this.type = type; + } + + public void setStatus(final Status status) { + this.status = status; + } + + public void setAuthToken(final String authToken) { + this.authToken = authToken; + } + + public void setRole(final String role) { + this.role = role; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AccountList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AccountList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AccountList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AccountList.java index c94c408492..f9b517f715 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AccountList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AccountList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Announcement.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Announcement.java similarity index 93% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Announcement.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Announcement.java index 43b87818d2..a58953377b 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Announcement.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Announcement.java @@ -17,13 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; /** * @author George Vagenas diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AnnouncementList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AnnouncementList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AnnouncementList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AnnouncementList.java index 7fa46b169c..200ab10e82 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AnnouncementList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AnnouncementList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author George Vagenas diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Application.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Application.java new file mode 100644 index 0000000000..2aaa8e18e0 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Application.java @@ -0,0 +1,222 @@ +/* + * 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.dao.entities; + +import java.net.URI; +import java.util.List; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; + +/** + * Represents a RestComm application + * + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ + +@Immutable +public final class Application { + private final Sid sid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final String friendlyName; + private final Sid accountSid; + private final String apiVersion; + private final Boolean hasVoiceCallerIdLookup; + private final URI uri; + private final URI rcmlUrl; + private final Kind kind; + private List numbers; + + public Application(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String friendlyName, + final Sid accountSid, final String apiVersion, final Boolean hasVoiceCallerIdLookup, final URI uri, + final URI rcmlUrl, Kind kind) { + this(sid, dateCreated, dateUpdated, friendlyName, accountSid, apiVersion,hasVoiceCallerIdLookup,uri,rcmlUrl,kind,null); + } + + public Application(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final String friendlyName, + final Sid accountSid, final String apiVersion, final Boolean hasVoiceCallerIdLookup, final URI uri, + final URI rcmlUrl, Kind kind, List numbers) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.friendlyName = friendlyName; + this.accountSid = accountSid; + this.apiVersion = apiVersion; + this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; + this.uri = uri; + this.rcmlUrl = rcmlUrl; + this.kind = kind; + this.numbers = numbers; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public String getFriendlyName() { + return friendlyName; + } + + public Sid getAccountSid() { + return accountSid; + } + + public String getApiVersion() { + return apiVersion; + } + + public Boolean hasVoiceCallerIdLookup() { + return hasVoiceCallerIdLookup; + } + + public URI getUri() { + return uri; + } + + public URI getRcmlUrl() { + return rcmlUrl; + } + + public Kind getKind() { + return kind; + } + + public List getNumbers() { + return numbers; + } + + public Application setFriendlyName(final String friendlyName) { + return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, + uri, rcmlUrl, kind); + } + + public Application setVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { + return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, + uri, rcmlUrl, kind); + } + + public Application setRcmlUrl(final URI rcmlUrl) { + return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, + uri, rcmlUrl, kind); + } + + public Application setKind(final Kind kind) { + return new Application(sid, dateCreated, DateTime.now(), friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, + uri, rcmlUrl, kind); + } + + public void setNumbers(List numbers) { + this.numbers = numbers; + } + + public enum Kind { + VOICE("voice"), SMS("sms"), USSD("ussd"); + + private final String text; + + private Kind(final String text) { + this.text = text; + } + + public static Kind getValueOf(final String text) { + Kind[] values = values(); + for (final Kind value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid application kind."); + } + + @Override + public String toString() { + return text; + } + }; + + public static final class Builder { + private Sid sid; + private String friendlyName; + private Sid accountSid; + private String apiVersion; + private Boolean hasVoiceCallerIdLookup; + private URI uri; + private URI rcmlUrl; + private Kind kind; + + private Builder() { + super(); + } + + public Application build() { + final DateTime now = DateTime.now(); + return new Application(sid, now, now, friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, uri, rcmlUrl, + kind); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setFriendlyName(final String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setAccountSid(final Sid accountSid) { + this.accountSid = accountSid; + } + + public void setApiVersion(final String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setHasVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { + this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + + public void setRcmlUrl(final URI rcmlUrl) { + this.rcmlUrl = rcmlUrl; + } + + public void setKind(final Kind kind) { + this.kind = kind; + } + + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ApplicationList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ApplicationList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationList.java index 2c0a8aa788..4715e08147 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ApplicationList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationNumberSummary.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationNumberSummary.java new file mode 100644 index 0000000000..04a84ad954 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ApplicationNumberSummary.java @@ -0,0 +1,72 @@ +/* + * 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.dao.entities; + +/** + * A summary entity for IncomingPhoneNumber to be nested inside the application + */ +public class ApplicationNumberSummary { + String sid; + String friendlyName; + String phoneNumber; + String voiceApplicationSid; + String smsApplicationSid; + String ussdApplicationSid; + String referApplicationSid; + + public ApplicationNumberSummary(String sid, String friendlyName, String phoneNumber, String voiceApplicationSid, String smsApplicationSid, String ussdApplicationSid, String referApplicationSid) { + this.sid = sid; + this.friendlyName = friendlyName; + this.phoneNumber = phoneNumber; + this.voiceApplicationSid = voiceApplicationSid; + this.smsApplicationSid = smsApplicationSid; + this.ussdApplicationSid = ussdApplicationSid; + this.referApplicationSid = referApplicationSid; + } + + public String getSid() { + return sid; + } + + public String getFriendlyName() { + return friendlyName; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getVoiceApplicationSid() { + return voiceApplicationSid; + } + + public String getSmsApplicationSid() { + return smsApplicationSid; + } + + public String getUssdApplicationSid() { + return ussdApplicationSid; + } + + public String getReferApplicationSid() { + return referApplicationSid; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumber.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumber.java similarity index 87% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumber.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumber.java index 640f129a11..2685052208 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumber.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumber.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -35,6 +35,7 @@ public final class AvailablePhoneNumber { private final String region; private final Integer postalCode; private final String isoCountry; + private final String cost; // Capabilities private final Boolean voiceCapable; @@ -44,14 +45,14 @@ public final class AvailablePhoneNumber { public AvailablePhoneNumber(final String friendlyName, final String phoneNumber, final Integer lata, final String rateCenter, final Double latitude, final Double longitude, final String region, - final Integer postalCode, final String isoCountry) { - this(friendlyName, phoneNumber, lata, rateCenter, latitude, longitude, region, postalCode, isoCountry, null, null, + final Integer postalCode, final String isoCountry, final String cost) { + this(friendlyName, phoneNumber, lata, rateCenter, latitude, longitude, region, postalCode, isoCountry, cost, null, null, null, null); } public AvailablePhoneNumber(final String friendlyName, final String phoneNumber, final Integer lata, final String rateCenter, final Double latitude, final Double longitude, final String region, - final Integer postalCode, final String isoCountry, final Boolean voiceCapable, final Boolean smsCapable, + final Integer postalCode, final String isoCountry, final String cost, final Boolean voiceCapable, final Boolean smsCapable, final Boolean mmsCapable, final Boolean faxCapable) { super(); this.friendlyName = friendlyName; @@ -63,6 +64,7 @@ public AvailablePhoneNumber(final String friendlyName, final String phoneNumber, this.region = region; this.postalCode = postalCode; this.isoCountry = isoCountry; + this.cost = cost; this.voiceCapable = voiceCapable; this.smsCapable = smsCapable; this.mmsCapable = mmsCapable; @@ -105,6 +107,10 @@ public String getIsoCountry() { return isoCountry; } + public String getCost() { + return cost; + } + public Boolean isVoiceCapable() { return this.voiceCapable; } @@ -123,6 +129,6 @@ public Boolean isFaxCapable() { public AvailablePhoneNumber setFriendlyName(final String friendlyName) { return new AvailablePhoneNumber(friendlyName, phoneNumber, lata, rateCenter, latitude, longitude, region, postalCode, - isoCountry, voiceCapable, smsCapable, mmsCapable, faxCapable); + isoCountry, cost, voiceCapable, smsCapable, mmsCapable, faxCapable); } } diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumberList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumberList.java similarity index 91% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumberList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumberList.java index 42e3f6233d..cb9650aa9a 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/AvailablePhoneNumberList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/AvailablePhoneNumberList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecord.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecord.java new file mode 100644 index 0000000000..b41dc9e5dd --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecord.java @@ -0,0 +1,490 @@ +/* + * 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.dao.entities; + +import java.math.BigDecimal; +import java.net.URI; +import java.util.Currency; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author pavel.slegr@telestax.com + */ +@Immutable +public final class CallDetailRecord { + private final Sid sid; + private final String instanceId; + private final Sid parentCallSid; + private final Sid conferenceSid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final Sid accountSid; + private final String to; + private final String from; + private final Sid phoneNumberSid; + private final String status; + private final DateTime startTime; + private final DateTime endTime; + private final Integer duration; + private final Integer ringDuration; + private final BigDecimal price; + private final Currency priceUnit; + private final String direction; + private final String answeredBy; + private final String apiVersion; + private final String forwardedFrom; + private final String callerName; + private final URI uri; + private final String callPath; + private final Boolean muted; + private final Boolean startConferenceOnEnter; + private final Boolean endConferenceOnExit; + private final Boolean onHold; + private final String msId; + + public CallDetailRecord(final Sid sid, final String instanceId, final Sid parentCallSid, final Sid conferenceSid, final DateTime dateCreated, final DateTime dateUpdated, + final Sid accountSid, final String to, final String from, final Sid phoneNumberSid, final String status, + final DateTime startTime, final DateTime endTime, final Integer duration, final BigDecimal price, + final Currency priceUnit, final String direction, final String answeredBy, final String apiVersion, + final String forwardedFrom, final String callerName, final URI uri, final String callPath,final Integer ringDuration, + final Boolean muted, final Boolean startConferenceOnEnter, final Boolean endConferenceOnExit, final Boolean onHold, final String msId) { + super(); + this.sid = sid; + this.instanceId = instanceId; + this.parentCallSid = parentCallSid; + this.conferenceSid = conferenceSid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.accountSid = accountSid; + this.to = to; + this.from = from; + this.phoneNumberSid = phoneNumberSid; + this.status = status; + this.startTime = startTime; + this.endTime = endTime; + this.duration = duration; + this.price = price; + this.priceUnit = priceUnit; + this.direction = direction; + this.answeredBy = answeredBy; + this.apiVersion = apiVersion; + this.forwardedFrom = forwardedFrom; + this.callerName = callerName; + this.uri = uri; + this.callPath = callPath; + this.ringDuration = ringDuration; + this.muted = muted; + this.startConferenceOnEnter = startConferenceOnEnter; + this.endConferenceOnExit = endConferenceOnExit; + this.onHold = onHold; + this.msId = msId; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public String getInstanceId() { return instanceId; } + + public Sid getParentCallSid() { + return parentCallSid; + } + + public Sid getConferenceSid() { + return conferenceSid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public Sid getAccountSid() { + return accountSid; + } + + public String getTo() { + return to; + } + + public String getFrom() { + return from; + } + + public Sid getPhoneNumberSid() { + return phoneNumberSid; + } + + public String getStatus() { + return status; + } + + public DateTime getStartTime() { + return startTime; + } + + public DateTime getEndTime() { + return endTime; + } + + public Integer getDuration() { + return duration; + } + + public Integer getRingDuration() { + return ringDuration; + } + + public BigDecimal getPrice() { + return (price == null) ? new BigDecimal("0.0") : price; + } + + public Currency getPriceUnit() { + return (priceUnit == null) ? Currency.getInstance("USD") : priceUnit; + } + + public String getDirection() { + return direction; + } + + public String getAnsweredBy() { + return answeredBy; + } + + public String getApiVersion() { + return apiVersion; + } + + public String getForwardedFrom() { + return forwardedFrom; + } + + public String getCallerName() { + return callerName; + } + + public URI getUri() { + return uri; + } + + public String getCallPath() { + return callPath; + } + + public Boolean isMuted() { + return muted; + } + + public Boolean isStartConferenceOnEnter() { + return startConferenceOnEnter; + } + + public Boolean isEndConferenceOnExit() { + return endConferenceOnExit; + } + + public Boolean isOnHold() { + return onHold; + } + + public String getMsId() { + return msId; + } + + public CallDetailRecord setStatus(final String status) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setStartTime(final DateTime startTime) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setEndTime(final DateTime endTime) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setDuration(final Integer duration) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setRingDuration(final Integer ringDuration) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setPrice(final BigDecimal price) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setAnsweredBy(final String answeredBy) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setConferenceSid(final Sid conferenceSid) { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setMuted(final Boolean muted){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setStartConferenceOnEnter(final Boolean startConferenceOnEnter){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setEndConferenceOnExit(final Boolean endConferenceOnExit){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setOnHold(final Boolean onHold){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setMsId(final String msId){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public CallDetailRecord setForwardedFrom(final String forwardedFrom){ + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, DateTime.now(), accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + @Override + public String toString() { + return "CDR SID: "+getSid()+" | InstanceId: "+getInstanceId()+" | ParentCallSid: "+getParentCallSid()+" | ConferenceSid: "+getConferenceSid()+" | DateCreated: "+getDateCreated()+" | DateUpdated: "+getDateUpdated()+" | AccountSid: "+getAccountSid()+" | To: "+getTo()+" | From: "+getFrom() + +" | PhoneNumberSid: "+getPhoneNumberSid()+" | Status: "+getStatus()+" | StartTime: "+getStartTime()+" | EndTime: "+getEndTime()+" | Duration: "+getDuration()+" | Price: "+getPrice()+" | PriceUnit: "+getPriceUnit()+" | Direction: "+getDirection()+" | AnsweredBy: "+getAnsweredBy() + +" | ApiVersion: "+getApiVersion()+" | ForwaredFrom: "+getForwardedFrom()+" | CallerName: "+getCallerName()+" | Uri: "+getUri()+" | CallPath: "+getCallPath()+" | RingDuration: "+getRingDuration()+" | Muted: "+isMuted()+" | StartConferenceOnEnter: "+isStartConferenceOnEnter() + +" | isEndConferenceOnExit: "+ isEndConferenceOnExit()+" | isOnHold: "+isOnHold(); + } + + @NotThreadSafe + public static final class Builder { + private Sid sid; + private String instanceId; + private Sid parentCallSid; + private Sid conferenceSid; + private DateTime dateCreated; + private DateTime dateUpdated; + private Sid accountSid; + private String to; + private String from; + private Sid phoneNumberSid; + private String status; + private DateTime startTime; + private DateTime endTime; + private Integer duration; + private Integer ringDuration; + private BigDecimal price; + private Currency priceUnit; + private String direction; + private String answeredBy; + private String apiVersion; + private String forwardedFrom; + private String callerName; + private URI uri; + private String callPath; + private Boolean muted; + private Boolean startConferenceOnEnter; + private Boolean endConferenceOnExit; + private Boolean onHold; + private String msId; + + private Builder() { + super(); + sid = null; + instanceId = null; + parentCallSid = null; + conferenceSid = null; + dateCreated = null; + dateUpdated = DateTime.now(); + accountSid = null; + to = null; + from = null; + phoneNumberSid = null; + status = null; + startTime = null; + endTime = null; + duration = null; + price = null; + direction = null; + answeredBy = null; + apiVersion = null; + forwardedFrom = null; + callerName = null; + uri = null; + callPath = null; + ringDuration = null; + muted = null; + startConferenceOnEnter = null; + endConferenceOnExit = null; + onHold = null; + msId = null; + } + + public CallDetailRecord build() { + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, dateUpdated, accountSid, to, from, phoneNumberSid, + status, startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, + callerName, uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setInstanceId(final String instanceId) { this.instanceId = instanceId; } + + public void setParentCallSid(final Sid parentCallSid) { + this.parentCallSid = parentCallSid; + } + + public void setConferenceSid(final Sid conferenceSid) { + this.conferenceSid = conferenceSid; + } + + public void setDateCreated(final DateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public void setAccountSid(final Sid accountSid) { + this.accountSid = accountSid; + } + + public void setTo(final String to) { + this.to = to; + } + + public void setFrom(final String from) { + this.from = from; + } + + public void setPhoneNumberSid(final Sid phoneNumberSid) { + this.phoneNumberSid = phoneNumberSid; + } + + public void setStatus(final String status) { + this.status = status; + } + + public void setStartTime(final DateTime startTime) { + this.startTime = startTime; + } + + public void setEndTime(final DateTime endTime) { + this.endTime = endTime; + } + + public void setDuration(final Integer duration) { + this.duration = duration; + } + + public void setPrice(final BigDecimal price) { + this.price = price; + } + + public void setPriceUnit(final Currency priceUnit) { + this.priceUnit = priceUnit; + } + + public void setDirection(final String direction) { + this.direction = direction; + } + + public void setAnsweredBy(final String answeredBy) { + this.answeredBy = answeredBy; + } + + public void setApiVersion(final String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setForwardedFrom(final String forwardedFrom) { + this.forwardedFrom = forwardedFrom; + } + + public void setCallerName(final String callerName) { + this.callerName = callerName; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + + public void setCallPath(final String callPath) { + this.callPath = callPath; + } + + public void setMuted(final Boolean muted) { + this.muted = muted; + } + + public void setStartConferenceOnEnter(final Boolean startConferenceOnEnter) { + this.startConferenceOnEnter = startConferenceOnEnter; + } + + public void setEndConferenceOnExit(final Boolean endConferenceOnExit) { + this.endConferenceOnExit = endConferenceOnExit; + } + + public void setOnHold(final Boolean onHold) { + this.onHold = onHold; + } + + public void setMsId(final String msId) { + this.msId = msId; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordFilter.java new file mode 100644 index 0000000000..c12e7edec1 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordFilter.java @@ -0,0 +1,139 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author gvagenas + */ + +@Immutable +public class CallDetailRecordFilter { + + private final String accountSid; + private final List accountSidSet; // if not-null we need the cdrs that belong to several accounts + private final String recipient; + private final String sender; + private final String status; + private final Date startTime; // to initialize it pass string arguments with yyyy-MM-dd format + private final Date endTime; + private final String parentCallSid; + private final String conferenceSid; + private final Integer limit; + private final Integer offset; + private final String instanceid; + + public CallDetailRecordFilter(String accountSid, List accountSidSet, String recipient, String sender, String status, String startTime, String endTime, + String parentCallSid, String conferenceSid, Integer limit, Integer offset) throws ParseException { + this(accountSid, accountSidSet, recipient,sender,status,startTime,endTime,parentCallSid, conferenceSid, limit,offset,null); + } + + public CallDetailRecordFilter(String accountSid, List accountSidSet, String recipient, String sender, String status, String startTime, String endTime, + String parentCallSid, String conferenceSid, Integer limit, Integer offset, String instanceId) throws ParseException { + this.accountSid = accountSid; + this.accountSidSet = accountSidSet; + + // The LIKE keyword uses '%' to match any (including 0) number of characters, and '_' to match exactly one character + // Add here the '%' keyword so +15126002188 will be the same as 15126002188 and 6002188 + if (recipient != null) + recipient = "%".concat(recipient); + if (sender != null) + sender = "%".concat(sender); + + this.recipient = recipient; + this.sender = sender; + this.status = status; + this.parentCallSid = parentCallSid; + this.conferenceSid = conferenceSid; + this.limit = limit; + this.offset = offset; + if (startTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(startTime); + this.startTime = date; + } else + this.startTime = null; + + if (endTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(endTime); + this.endTime = date; + } else { + this.endTime = null; + } + if (instanceId != null && !instanceId.isEmpty()) { + this.instanceid = instanceId; + } else { + this.instanceid = null; + } + } + + public String getSid() { + return accountSid; + } + + public List getAccountSidSet() { + return accountSidSet; + } + + public String getRecipient() { + return recipient; + } + + public String getSender() { + return sender; + } + + public String getStatus() { + return status; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public String getParentCallSid() { + return parentCallSid; + } + + public String getConferenceSid() { + return conferenceSid; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getInstanceid() { return instanceid; } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordList.java index 2a05a21042..d44e725765 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallDetailRecordList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallDetailRecordList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallStatus.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallStatus.java similarity index 84% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallStatus.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallStatus.java index 1c21482799..003743a103 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/CallStatus.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/CallStatus.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; /** * @author gvagenas diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Client.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Client.java similarity index 84% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Client.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Client.java index 5c9c9d68f8..504bb50154 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Client.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Client.java @@ -17,14 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -49,11 +50,12 @@ public final class Client { private final String voiceFallbackMethod; private final Sid voiceApplicationSid; private final URI uri; + private final String pushClientIdentity; public Client(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final Sid accountSid, final String apiVersion, final String friendlyName, final String login, final String password, final Integer status, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, - String voiceFallbackMethod, final Sid voiceApplicationSid, final URI uri) { + String voiceFallbackMethod, final Sid voiceApplicationSid, final URI uri, final String pushClientIdentity) { super(); this.sid = sid; this.dateCreated = dateCreated; @@ -70,6 +72,7 @@ public Client(final Sid sid, final DateTime dateCreated, final DateTime dateUpda this.voiceFallbackMethod = voiceFallbackMethod; this.voiceApplicationSid = voiceApplicationSid; this.uri = uri; + this.pushClientIdentity = pushClientIdentity; } public static Builder builder() { @@ -136,44 +139,53 @@ public URI getUri() { return uri; } + public String getPushClientIdentity() { + return pushClientIdentity; + } + public Client setFriendlyName(final String friendlyName) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setPassword(final String password) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setStatus(final int status) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setVoiceUrl(final URI voiceUrl) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setVoiceMethod(final String voiceMethod) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setVoiceFallbackUrl(final URI voiceFallbackUrl) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setVoiceFallbackMethod(final String voiceFallbackMethod) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public Client setVoiceApplicationSid(final Sid voiceApplicationSid) { return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); + } + + public Client setPushClientIdentity(final String pushClientIdentity) { + return new Client(sid, dateCreated, DateTime.now(), accountSid, apiVersion, friendlyName, login, password, status, + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } @NotThreadSafe @@ -191,6 +203,7 @@ public static final class Builder { private String voiceFallbackMethod; private Sid voiceApplicationSid; private URI uri; + private String pushClientIdentity; private Builder() { super(); @@ -199,7 +212,7 @@ private Builder() { public Client build() { final DateTime now = DateTime.now(); return new Client(sid, now, now, accountSid, apiVersion, friendlyName, login, password, status, voiceUrl, - voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } public void setSid(final Sid sid) { @@ -253,5 +266,9 @@ public void setVoiceApplicationSid(final Sid voiceApplicationSid) { public void setUri(final URI uri) { this.uri = uri; } + + public void setPushClientIdentity(String pushClientIdentity) { + this.pushClientIdentity = pushClientIdentity; + } } } diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ClientList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ClientList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ClientList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ClientList.java index 7c020fa4b0..6accfb4dbd 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ClientList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ClientList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecord.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecord.java new file mode 100644 index 0000000000..fe8eb65d43 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecord.java @@ -0,0 +1,283 @@ +/* + * 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.dao.entities; + +import java.net.URI; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@Immutable +public final class ConferenceDetailRecord { + private final Sid sid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final Sid accountSid; + private final String status; + private final String friendlyName; + private final String apiVersion; + private final URI uri; + private final String masterMsId; + private final boolean masterPresent; + private final String masterConfernceEndpointId; + private final String masterIVREndpointId; + private final String masterIVREndpointSessionId; + private final String masterBridgeEndpointId; + private final String masterBridgeEndpointSessionId; + private final String masterBridgeConnectionIdentifier; + private final String masterIVRConnectionIdentifier; + private final boolean moderatorPresent; + + public ConferenceDetailRecord(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final Sid accountSid, + final String status, final String friendlyName, final String apiVersion, final URI uri, final String msId, + final String masterConfernceEndpointId, final boolean isMasterPresent, final String masterIVREndpointId, final String masterIVREndpointSessionId, + final String masterBridgeEndpointId, final String masterBridgeEndpointSessionId, final String masterBridgeConnectionIdentifier, + final String masterIVRConnectionIdentifier, final boolean moderatorPresent) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.accountSid = accountSid; + this.status = status; + this.friendlyName = friendlyName; + this.apiVersion = apiVersion; + this.uri = uri; + this.masterMsId = msId; + this.masterConfernceEndpointId = masterConfernceEndpointId; + this.masterPresent = isMasterPresent; + this.masterIVREndpointId = masterIVREndpointId; + this.masterIVREndpointSessionId = masterIVREndpointSessionId; + this.masterBridgeEndpointId = masterBridgeEndpointId; + this.masterBridgeEndpointSessionId = masterBridgeEndpointSessionId; + this.masterBridgeConnectionIdentifier = masterBridgeConnectionIdentifier; + this.masterIVRConnectionIdentifier = masterIVRConnectionIdentifier; + this.moderatorPresent = moderatorPresent; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public Sid getAccountSid() { + return accountSid; + } + + public String getStatus() { + return status; + } + + public String getFriendlyName() { + return friendlyName; + } + + public String getApiVersion() { + return apiVersion; + } + + public URI getUri() { + return uri; + } + + public String getMasterMsId() { + return masterMsId; + } + + public String getMasterConferenceEndpointId() { + return masterConfernceEndpointId; + } + + public String getMasterBridgeEndpointId() { + return masterBridgeEndpointId; + } + + public String getMasterIVREndpointId() { + return masterIVREndpointId; + } + + public String getMasterIVREndpointSessionId() { + return masterIVREndpointSessionId; + } + + public String getMasterBridgeEndpointSessionId() { + return masterBridgeEndpointSessionId; + } + + public boolean isMasterPresent() { + return masterPresent; + } + + public String getMasterBridgeConnectionIdentifier() { + return masterBridgeConnectionIdentifier; + } + + public String getMasterIVRConnectionIdentifier() { + return masterIVRConnectionIdentifier; + } + + public boolean isModeratorPresent() { + return moderatorPresent; + } + + public ConferenceDetailRecord setStatus(final String status) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterConfernceEndpointId(final String masterConfernceEndpointId) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterIVREndpointId(final String masterIVREndpointId) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterIVREndpointSessionId(final String masterIVREndpointSessionId) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterBridgeEndpointSessionId(final String masterBridgeEndpointSessionId) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterBridgeEndpointId(final String masterBridgeEndpointId) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterBridgeConnectionIdentifier(final String masterBridgeConnectionIdentifier) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterIVRConnectionIdentifier(final String masterIVRConnectionIdentifier) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setMasterPresent(final boolean masterPresent) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + public ConferenceDetailRecord setModeratorPresent(final boolean moderatorPresent) { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + @NotThreadSafe + public static final class Builder { + private Sid sid; + private DateTime dateCreated; + private Sid accountSid; + private String status; + private String friendlyName; + private String apiVersion; + private URI uri; + private String masterMsId; + private String masterConfernceEndpointId; + private String masterIVREndpointId; + private boolean isMasterPresent; + + private Builder() { + super(); + sid = null; + dateCreated = null; + accountSid = null; + status = null; + friendlyName = null; + apiVersion = null; + uri = null; + masterMsId = null; + masterConfernceEndpointId = null; + masterIVREndpointId = null; + isMasterPresent = true; + } + + public ConferenceDetailRecord build() { + return new ConferenceDetailRecord(sid, dateCreated, DateTime.now(), accountSid, + status, friendlyName, apiVersion, uri, masterMsId, masterConfernceEndpointId, isMasterPresent, masterIVREndpointId, null, null, null, null, null, false); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setMasterMsId(final String msId) { + this.masterMsId = msId; + } + + public void setDateCreated(final DateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public void setAccountSid(final Sid accountSid) { + this.accountSid = accountSid; + } + + public void setStatus(final String status) { + this.status = status; + } + + public void setFriendlyName(final String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setApiVersion(final String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + + public void setMasterConfernceEndpointId(final String masterConfernceEndpointId) { + this.masterConfernceEndpointId = masterConfernceEndpointId; + } + + public void setMasterIVREndpointId(final String masterIVREndpointId) { + this.masterIVREndpointId = masterIVREndpointId; + } + } + + @Override + public String toString() { + return "ConferenceDetailRecord [sid=" + sid + ", dateCreated=" + dateCreated + ", dateUpdated=" + dateUpdated + + ", accountSid=" + accountSid + ", status=" + status + ", friendlyName=" + friendlyName + + ", apiVersion=" + apiVersion + ", uri=" + uri + ", masterMsId=" + masterMsId + ", masterPresent=" + + masterPresent + ", masterConfernceEndpointId=" + masterConfernceEndpointId + ", masterIVREndpointId=" + + masterIVREndpointId + ", masterIVREndpointSessionId=" + masterIVREndpointSessionId + + ", masterBridgeEndpointId=" + masterBridgeEndpointId + ", masterBridgeEndpointSessionId=" + + masterBridgeEndpointSessionId + ", masterBridgeConnectionIdentifier=" + + masterBridgeConnectionIdentifier + ", masterIVRConnectionIdentifier=" + masterIVRConnectionIdentifier + + ", moderatorPresent=" + moderatorPresent + "]"; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordFilter.java new file mode 100644 index 0000000000..fd1efa2279 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordFilter.java @@ -0,0 +1,93 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2014, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it and/or modify + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ +package org.restcomm.connect.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ + +@Immutable +public class ConferenceDetailRecordFilter { + + private final String accountSid; + private final String status; + private final Date dateCreated; + private final Date dateUpdated; + private final String friendlyName; + private final Integer limit; + private final Integer offset; + + public ConferenceDetailRecordFilter(String accountSid, String status, String dateCreated, String dateUpdated, + String friendlyName, Integer limit, Integer offset) throws ParseException { + this.accountSid = accountSid; + this.status = status; + this.friendlyName = friendlyName; + this.limit = limit; + this.offset = offset; + if (dateCreated != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(dateCreated); + this.dateCreated = date; + } else + this.dateCreated = null; + + if (dateUpdated != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(dateUpdated); + this.dateUpdated = date; + } else + this.dateUpdated = null; + } + + public String getSid() { + return accountSid; + } + + public String getStatus() { + return status; + } + + public String getFriendlyName() { + return friendlyName; + } + + public Date getDateCreated() { + return dateCreated; + } + + public Date getDateUpdated() { + return dateUpdated; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordList.java new file mode 100644 index 0000000000..93b94e76c6 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceDetailRecordList.java @@ -0,0 +1,41 @@ +/* + * 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.dao.entities; + +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@NotThreadSafe +public final class ConferenceDetailRecordList { + private final List cdrs; + + public ConferenceDetailRecordList(final List cdrs) { + super(); + this.cdrs = cdrs; + } + + public List getConferenceDetailRecords() { + return cdrs; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceRecordCountFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceRecordCountFilter.java new file mode 100644 index 0000000000..61bd4ab654 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ConferenceRecordCountFilter.java @@ -0,0 +1,159 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +@Immutable +public class ConferenceRecordCountFilter { + + private final String accountSid; + private final String status; + private final Date dateCreated; + private final Date dateUpdated; + private final String friendlyName; + private final Integer limit; + private final Integer offset; + private final String masterMsId; + + public ConferenceRecordCountFilter(String accountSid, String status, String dateCreated, String dateUpdated, + String friendlyName, Integer limit, Integer offset, String masterMsId) throws ParseException { + this.accountSid = accountSid; + this.status = status; + this.friendlyName = friendlyName; + this.limit = limit; + this.offset = offset; + this.masterMsId = masterMsId; + if (dateCreated != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(dateCreated); + this.dateCreated = date; + } else { + this.dateCreated = null; + } + + if (dateUpdated != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(dateUpdated); + this.dateUpdated = date; + } else { + this.dateUpdated = null; + } + } + + public String getSid() { + return accountSid; + } + + public String getStatus() { + return status; + } + + public String getFriendlyName() { + return friendlyName; + } + + public Date getDateCreated() { + return dateCreated; + } + + public Date getDateUpdated() { + return dateUpdated; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getMasterMsId() { + return masterMsId; + } + + public static ConferenceRecordCountFilter.Builder builder() { + return new ConferenceRecordCountFilter.Builder(); + } + + public static final class Builder { + + private String accountSid = null; + private String status = null; + private String dateCreated = null; + private String dateUpdated = null; + private String friendlyName = null; + private Integer limit = null; + private Integer offset = null; + private String masterMsId = null; + + public ConferenceRecordCountFilter build() throws ParseException { + return new ConferenceRecordCountFilter(accountSid, status, dateCreated, dateUpdated, friendlyName, limit, offset, masterMsId); + } + public Builder byAccountSid(String accountSid) { + this.accountSid = accountSid; + return this; + } + + public Builder byStatus(String status) { + this.status = status; + return this; + } + + public Builder byDateCreated(String dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + public Builder byDateUpdated(String dateUpdated) { + this.dateUpdated = dateUpdated; + return this; + } + + public Builder byFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + public Builder byLimit(Integer limit) { + this.limit = limit; + return this; + } + + public Builder byOffset(Integer offset) { + this.offset = offset; + return this; + } + + public Builder byMasterMsId(String masterMsId) { + this.masterMsId = masterMsId; + return this; + } + + + + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Gateway.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Gateway.java similarity index 95% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Gateway.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Gateway.java index 89cb8e430c..2bacd12b10 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Gateway.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Gateway.java @@ -17,15 +17,16 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.io.Serializable; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/GatewayList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GatewayList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/GatewayList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GatewayList.java index 528701047a..e1112af0f5 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/GatewayList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GatewayList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Geolocation.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Geolocation.java new file mode 100644 index 0000000000..66a054c47b --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Geolocation.java @@ -0,0 +1,674 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao.entities; + +import java.net.URI; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author Fernando Mendioroz + * + */ +public final class Geolocation { + + private final Sid sid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final DateTime dateExecuted; + private final Sid accountSid; + private final String source; + private final String deviceIdentifier; + private final GeolocationType geolocationType; + private final String responseStatus; + private final String cellId; + private final String locationAreaCode; + private final Integer mobileCountryCode; + private final String mobileNetworkCode; + private final Long networkEntityAddress; + private final Integer ageOfLocationInfo; + private final String deviceLatitude; + private final String deviceLongitude; + private final Long accuracy; + private final String physicalAddress; + private final String internetAddress; + private final String formattedAddress; + private final DateTime locationTimestamp; + private final String eventGeofenceLatitude; + private final String eventGeofenceLongitude; + private final Long radius; + private final String geolocationPositioningType; + private final String lastGeolocationResponse; + private final String cause; + private final String apiVersion; + private final URI uri; + + public Geolocation(Sid sid, DateTime dateCreated, DateTime dateUpdated, DateTime dateExecuted, Sid accountSid, + String source, String deviceIdentifier, GeolocationType geolocationType, String responseStatus, String cellId, + String locationAreaCode, Integer mobileCountryCode, String mobileNetworkCode, Long networkEntityAddress, + Integer ageOfLocationInfo, String deviceLatitude, String deviceLongitude, Long accuracy, String physicalAddress, + String internetAddress, String formattedAddress, DateTime locationTimestamp, String eventGeofenceLatitude, + String eventGeofenceLongitude, Long radius, String geolocationPositioningType, String lastGeolocationResponse, + String cause, String apiVersion, URI uri) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.dateExecuted = dateExecuted; + this.accountSid = accountSid; + this.source = source; + this.deviceIdentifier = deviceIdentifier; + this.geolocationType = geolocationType; + this.responseStatus = responseStatus; + this.cellId = cellId; + this.locationAreaCode = locationAreaCode; + this.mobileCountryCode = mobileCountryCode; + this.mobileNetworkCode = mobileNetworkCode; + this.networkEntityAddress = networkEntityAddress; + this.ageOfLocationInfo = ageOfLocationInfo; + this.deviceLatitude = deviceLatitude; + this.deviceLongitude = deviceLongitude; + this.accuracy = accuracy; + this.physicalAddress = physicalAddress; + this.internetAddress = internetAddress; + this.formattedAddress = formattedAddress; + this.locationTimestamp = locationTimestamp; + this.eventGeofenceLatitude = eventGeofenceLatitude; + this.eventGeofenceLongitude = eventGeofenceLongitude; + this.radius = radius; + this.geolocationPositioningType = geolocationPositioningType; + this.lastGeolocationResponse = lastGeolocationResponse; + this.cause = cause; + this.apiVersion = apiVersion; + this.uri = uri; + } + + public Sid getSid() { + return sid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public DateTime getDateExecuted() { + return dateExecuted; + } + + public Sid getAccountSid() { + return accountSid; + } + + public String getSource() { + return source; + } + + public String getDeviceIdentifier() { + return deviceIdentifier; + } + + public GeolocationType getGeolocationType() { + return geolocationType; + } + + public String getResponseStatus() { + return responseStatus; + } + + public String getCellId() { + return cellId; + } + + public String getLocationAreaCode() { + return locationAreaCode; + } + + public Integer getMobileCountryCode() { + return mobileCountryCode; + } + + public String getMobileNetworkCode() { + return mobileNetworkCode; + } + + public Long getNetworkEntityAddress() { + return networkEntityAddress; + } + + public Integer getAgeOfLocationInfo() { + return ageOfLocationInfo; + } + + public String getDeviceLatitude() { + return deviceLatitude; + } + + public String getDeviceLongitude() { + return deviceLongitude; + } + + public Long getAccuracy() { + return accuracy; + } + + public String getPhysicalAddress() { + return physicalAddress; + } + + public String getInternetAddress() { + return internetAddress; + } + + public String getFormattedAddress() { + return formattedAddress; + } + + public DateTime getLocationTimestamp() { + return locationTimestamp; + } + + public String getEventGeofenceLatitude() { + return eventGeofenceLatitude; + } + + public String getEventGeofenceLongitude() { + return eventGeofenceLongitude; + } + + public Long getRadius() { + return radius; + } + + public String getGeolocationPositioningType() { + return geolocationPositioningType; + } + + public String getLastGeolocationResponse() { + return lastGeolocationResponse; + } + + public String getCause() { + return cause; + } + + public String getApiVersion() { + return apiVersion; + } + + public URI getUri() { + return uri; + } + + public enum GeolocationType { + Immediate("Immediate"), Notification("Notification"); + + private final String glt; + + private GeolocationType(final String glt) { + this.glt = glt; + } + + public static GeolocationType getValueOf(final String glt) { + GeolocationType[] values = values(); + for (final GeolocationType value : values) { + if (value.toString().equals(glt)) { + return value; + } + } + throw new IllegalArgumentException(glt + " is not a valid GeolocationType."); + } + + @Override + public String toString() { + return glt; + } + }; + + public Geolocation setSid(Sid sid) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDateCreated(DateTime dateCreated) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDateUpdated(DateTime dateUpdated) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDateExecuted(DateTime dateExecuted) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setAccountSid(Sid accountSid) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setSource(String source) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDeviceIdentifier(String deviceIdentifier) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setGeolocationType(GeolocationType geolocationType) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setResponseStatus(String responseStatus) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setCellId(String cellId) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setLocationAreaCode(String locationAreaCode) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setLocationTimestamp(DateTime locationTimestamp) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setMobileCountryCode(Integer mobileCountryCode) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setMobileNetworkCode(String mobileNetworkCode) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setNetworkEntityAddress(Long networkEntityAddress) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setAgeOfLocationInfo(Integer ageOfLocationInfo) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDeviceLatitude(String deviceLatitude) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setDeviceLongitude(String deviceLongitude) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setAccuracy(Long accuracy) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setPhysicalAddress(String physicalAddress) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setInternetAddress(String internetAddress) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setFormattedAddress(String formattedAddress) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setEventGeofenceLatitude(String eventGeofenceLatitude) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setEventGeofenceLongitude(String eventGeofenceLongitude) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setRadius(Long radius) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setGeolocationPositioningType(String geolocationPositioningType) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setLastGeolocationResponse(String lastGeolocationResponse) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setCause(String cause) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setApiVersion(String apiVersion) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public Geolocation setUri(URI uri) { + return new Geolocation(sid, dateCreated, dateUpdated, dateExecuted, accountSid, source, deviceIdentifier, + geolocationType, responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, + networkEntityAddress, ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, + internetAddress, formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public static Builder builder() { + return new Builder(); + } + + @NotThreadSafe + public static final class Builder { + + private Sid sid; + private DateTime dateUpdated; + private Sid accountSid; + private String source; + private String deviceIdentifier; + private GeolocationType geolocationType; + private String responseStatus; + private String cellId; + private String locationAreaCode; + private Integer mobileCountryCode; + private String mobileNetworkCode; + private Long networkEntityAddress; + private Integer ageOfLocationInfo; + private String deviceLatitude; + private String deviceLongitude; + private Long accuracy; + private String physicalAddress; + private String internetAddress; + private String formattedAddress; + private DateTime locationTimestamp; + private String eventGeofenceLatitude; + private String eventGeofenceLongitude; + private Long radius; + private String geolocationPositioningType; + private String lastGeolocationResponse; + private String cause; + private String apiVersion; + private URI uri; + + private Builder() { + super(); + } + + public Geolocation build() { + final DateTime now = DateTime.now(); + return new Geolocation(sid, now, dateUpdated, now, accountSid, source, deviceIdentifier, geolocationType, + responseStatus, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, networkEntityAddress, + ageOfLocationInfo, deviceLatitude, deviceLongitude, accuracy, physicalAddress, internetAddress, + formattedAddress, locationTimestamp, eventGeofenceLatitude, eventGeofenceLongitude, radius, + geolocationPositioningType, lastGeolocationResponse, cause, apiVersion, uri); + } + + public void setSid(Sid sid) { + this.sid = sid; + } + + public void setDateUpdated(DateTime dateUpdated) { + this.dateUpdated = dateUpdated; + } + + public void setAccountSid(Sid accountSid) { + this.accountSid = accountSid; + } + + public void setSource(String source) { + this.source = source; + } + + public void setDeviceIdentifier(String deviceIdentifier) { + this.deviceIdentifier = deviceIdentifier; + } + + public void setGeolocationType(GeolocationType geolocationType) { + this.geolocationType = geolocationType; + } + + public void setResponseStatus(String responseStatus) { + this.responseStatus = responseStatus; + } + + public void setCellId(String cellId) { + this.cellId = cellId; + } + + public void setLocationAreaCode(String locationAreaCode) { + this.locationAreaCode = locationAreaCode; + } + + public void setMobileCountryCode(Integer mobileCountryCode) { + this.mobileCountryCode = mobileCountryCode; + } + + public void setMobileNetworkCode(String mobileNetworkCode) { + this.mobileNetworkCode = mobileNetworkCode; + } + + public void setNetworkEntityAddress(Long networkEntityAddress) { + this.networkEntityAddress = networkEntityAddress; + } + + public void setAgeOfLocationInfo(Integer ageOfLocationInfo) { + this.ageOfLocationInfo = ageOfLocationInfo; + } + + public void setDeviceLatitude(String devLatitude) { + this.deviceLatitude = devLatitude; + } + + public void setDeviceLongitude(String devLongitude) { + this.deviceLongitude = devLongitude; + } + + public void setAccuracy(Long accuracy) { + this.accuracy = accuracy; + } + + public void setPhysicalAddress(String physicalAddress) { + this.physicalAddress = physicalAddress; + } + + public void setInternetAddress(String internetAddress) { + this.internetAddress = internetAddress; + } + + public void setFormattedAddress(String formattedAddress) { + this.formattedAddress = formattedAddress; + } + + public void setLocationTimestamp(DateTime locationTimestamp) { + try { + this.locationTimestamp = locationTimestamp; + } catch (Exception exception) { + DateTime locTimestamp = DateTime.parse("1900-01-01"); + this.locationTimestamp = locTimestamp; + } + } + + public void setEventGeofenceLatitude(String eventGeofenceLat) { + this.eventGeofenceLatitude = eventGeofenceLat; + } + + public void setEventGeofenceLongitude(String eventGeofenceLong) { + this.eventGeofenceLongitude = eventGeofenceLong; + } + + public void setRadius(Long radius) { + if (geolocationType.toString().equals(GeolocationType.Notification)) { + this.radius = radius; + } else { + this.radius = null; + } + } + + public void setGeolocationPositioningType(String geolocationPositioningType) { + this.geolocationPositioningType = geolocationPositioningType; + } + + public void setLastGeolocationResponse(String lastGeolocationResponse) { + this.lastGeolocationResponse = lastGeolocationResponse; + } + + public void setCause(String cause) { + if (responseStatus != null && (responseStatus.equalsIgnoreCase("rejected") + || responseStatus.equalsIgnoreCase("unauthorized") || responseStatus.equalsIgnoreCase("failed"))) { + this.cause = cause; + // "cause" is only updated if "responseStatus" is not null and is either "rejected", "unauthorized" or "failed" + // Otherwise, it's value in HTTP POST/PUT is ignored + } + if (responseStatus != null && (!responseStatus.equalsIgnoreCase("rejected") + && !responseStatus.equalsIgnoreCase("unauthorized") && !responseStatus.equalsIgnoreCase("failed"))) { + this.cause = null; + // "cause" is set to null if "responseStatus" is not null and is neither "rejected", "unauthorized" nor "failed" + } + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setUri(URI uri) { + this.uri = uri; + } + + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GeolocationList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GeolocationList.java new file mode 100644 index 0000000000..effb156ace --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/GeolocationList.java @@ -0,0 +1,46 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao.entities; + +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author Fernando Mendioroz + * + */ +@NotThreadSafe +public final class GeolocationList { + + private final List geolocations; + + public GeolocationList(final List geolocations) { + super(); + this.geolocations = geolocations; + } + + public List getGeolocations() { + return geolocations; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumber.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumber.java new file mode 100644 index 0000000000..b332b42f37 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumber.java @@ -0,0 +1,946 @@ +/* + * 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.dao.entities; + +import java.net.URI; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@Immutable +public final class IncomingPhoneNumber { + private Sid sid; + private DateTime dateCreated; + private DateTime dateUpdated; + private String friendlyName; + private Sid accountSid; + private String phoneNumber; + private String cost; + private String apiVersion; + private Boolean hasVoiceCallerIdLookup; + private URI voiceUrl; + private String voiceMethod; + private URI voiceFallbackUrl; + private String voiceFallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private Sid voiceApplicationSid; + private String voiceApplicationName; + private URI smsUrl; + private String smsMethod; + private URI smsFallbackUrl; + private String smsFallbackMethod; + private Sid smsApplicationSid; + private String smsApplicationName; + private URI uri; + private URI ussdUrl; + private String ussdMethod; + private URI ussdFallbackUrl; + private String ussdFallbackMethod; + private Sid ussdApplicationSid; + private String ussdApplicationName; + private URI referUrl; + private String referMethod; + private Sid referApplicationSid; + private String referApplicationName; + private Sid organizationSid; + + // Capabilities + private Boolean voiceCapable; + private Boolean smsCapable; + private Boolean mmsCapable; + private Boolean faxCapable; + private Boolean pureSip; + + public IncomingPhoneNumber(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, + final String friendlyName, final Sid accountSid, final String phoneNumber, final String cost, final String apiVersion, + final Boolean hasVoiceCallerIdLookup, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, + final String voiceFallbackMethod, final URI statusCallback, final String statusCallbackMethod, + final Sid voiceApplicationSid, final URI smsUrl, final String smsMethod, final URI smsFallbackUrl, + final String smsFallbackMethod, final Sid smsApplicationSid, final URI uri, final URI ussdUrl, final String ussdMethod, final URI ussdFallbackUrl, + final String ussdFallbackMethod, final Sid ussdApplicationSid, + final URI referUrl, final String referMethod, final Sid referApplicationSid, final Sid organizationSid) { + this(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, cost, apiVersion, hasVoiceCallerIdLookup, + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, + voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, referUrl, referMethod, referApplicationSid, null, null, null, null, null, organizationSid); + } + + public IncomingPhoneNumber(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, + final String friendlyName, final Sid accountSid, final String phoneNumber, final String cost, final String apiVersion, + final Boolean hasVoiceCallerIdLookup, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, + final String voiceFallbackMethod, final URI statusCallback, final String statusCallbackMethod, + final Sid voiceApplicationSid, final URI smsUrl, final String smsMethod, final URI smsFallbackUrl, + final String smsFallbackMethod, final Sid smsApplicationSid, final URI uri, final URI ussdUrl, final String ussdMethod, final URI ussdFallbackUrl, + final String ussdFallbackMethod, final Sid ussdApplicationSid, + final URI referUrl, final String referMethod, final Sid referApplicationSid, + final Boolean voiceCapable, + final Boolean smsCapable, final Boolean mmsCapable, final Boolean faxCapable, final Boolean pureSip, final Sid organizationSid) { + this(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, cost, apiVersion, hasVoiceCallerIdLookup, + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, statusCallbackMethod, + voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, + referUrl, referMethod, referApplicationSid, + voiceCapable, smsCapable, mmsCapable, faxCapable, pureSip, null, null, null, null, organizationSid); + } + + public IncomingPhoneNumber(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, + final String friendlyName, final Sid accountSid, final String phoneNumber, final String cost, final String apiVersion, + final Boolean hasVoiceCallerIdLookup, final URI voiceUrl, final String voiceMethod, final URI voiceFallbackUrl, + final String voiceFallbackMethod, final URI statusCallback, final String statusCallbackMethod, + final Sid voiceApplicationSid, final URI smsUrl, final String smsMethod, final URI smsFallbackUrl, + final String smsFallbackMethod, final Sid smsApplicationSid, final URI uri, final URI ussdUrl, final String ussdMethod, final URI ussdFallbackUrl, + final String ussdFallbackMethod, final Sid ussdApplicationSid, + final URI referUrl, final String referMethod, final Sid referApplicationSid, + final Boolean voiceCapable, + final Boolean smsCapable, final Boolean mmsCapable, final Boolean faxCapable, final Boolean pureSip, final String voiceApplicationName, final String smsApplicationName, final String ussdApplicationName, final String referApplicationName, final Sid organizationSid) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.friendlyName = friendlyName; + this.accountSid = accountSid; + this.phoneNumber = phoneNumber; + this.cost = cost; + this.apiVersion = apiVersion; + this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; + this.voiceUrl = voiceUrl; + this.voiceMethod = voiceMethod; + this.voiceFallbackUrl = voiceFallbackUrl; + this.voiceFallbackMethod = voiceFallbackMethod; + this.statusCallback = statusCallback; + this.statusCallbackMethod = statusCallbackMethod; + this.voiceApplicationSid = voiceApplicationSid; + this.smsUrl = smsUrl; + this.smsMethod = smsMethod; + this.smsFallbackUrl = smsFallbackUrl; + this.smsFallbackMethod = smsFallbackMethod; + this.smsApplicationSid = smsApplicationSid; + this.uri = uri; + this.ussdUrl = ussdUrl; + this.ussdMethod = ussdMethod; + this.ussdFallbackUrl = ussdFallbackUrl; + this.ussdFallbackMethod = ussdFallbackMethod; + this.ussdApplicationSid = ussdApplicationSid; + this.referUrl = referUrl; + this.referMethod = referMethod; + this.referApplicationSid = referApplicationSid; + this.voiceCapable = voiceCapable; + this.smsCapable = smsCapable; + this.mmsCapable = mmsCapable; + this.faxCapable = faxCapable; + this.pureSip = pureSip; + this.voiceApplicationName = voiceApplicationName; + this.smsApplicationName = smsApplicationName; + this.ussdApplicationName = ussdApplicationName; + this.referApplicationName = referApplicationName; + this.organizationSid = organizationSid; + } + + /** + * @return the sid + */ + public Sid getSid() { + return sid; + } + + /** + * @param sid the sid to set + */ + public void setSid(Sid sid) { + this.sid = sid; + } + + /** + * @return the dateCreated + */ + public DateTime getDateCreated() { + return dateCreated; + } + + /** + * @param dateCreated the dateCreated to set + */ + public void setDateCreated(DateTime dateCreated) { + this.dateCreated = dateCreated; + } + + /** + * @return the dateUpdated + */ + public DateTime getDateUpdated() { + return dateUpdated; + } + + /** + * @param dateUpdated the dateUpdated to set + */ + public void setDateUpdated(DateTime dateUpdated) { + this.dateUpdated = dateUpdated; + } + + /** + * @return the friendlyName + */ + public String getFriendlyName() { + return friendlyName; + } + + /** + * @param friendlyName the friendlyName to set + */ + public void setFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + } + + /** + * @return the accountSid + */ + public Sid getAccountSid() { + return accountSid; + } + + /** + * @param accountSid the accountSid to set + */ + public void setAccountSid(Sid accountSid) { + this.accountSid = accountSid; + } + + /** + * @return the phoneNumber + */ + public String getPhoneNumber() { + return phoneNumber; + } + + /** + * @param phoneNumber the phoneNumber to set + */ + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + /** + * @return the cost + */ + public String getCost() { + return cost; + } + + /** + * @param cost the cost to set + */ + public void setCost(String cost) { + this.cost = cost; + } + + /** + * @return the apiVersion + */ + public String getApiVersion() { + return apiVersion; + } + + /** + * @param apiVersion the apiVersion to set + */ + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * @return the hasVoiceCallerIdLookup + */ + public Boolean hasVoiceCallerIdLookup() { + return hasVoiceCallerIdLookup; + } + + /** + * @param hasVoiceCallerIdLookup the hasVoiceCallerIdLookup to set + */ + public void setHasVoiceCallerIdLookup(Boolean hasVoiceCallerIdLookup) { + this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; + } + + /** + * @return the voiceUrl + */ + public URI getVoiceUrl() { + return voiceUrl; + } + + /** + * @param voiceUrl the voiceUrl to set + */ + public void setVoiceUrl(URI voiceUrl) { + this.voiceUrl = voiceUrl; + } + + /** + * @return the voiceMethod + */ + public String getVoiceMethod() { + return voiceMethod; + } + + /** + * @param voiceMethod the voiceMethod to set + */ + public void setVoiceMethod(String voiceMethod) { + this.voiceMethod = voiceMethod; + } + + /** + * @return the voiceFallbackUrl + */ + public URI getVoiceFallbackUrl() { + return voiceFallbackUrl; + } + + /** + * @param voiceFallbackUrl the voiceFallbackUrl to set + */ + public void setVoiceFallbackUrl(URI voiceFallbackUrl) { + this.voiceFallbackUrl = voiceFallbackUrl; + } + + /** + * @return the voiceFallbackMethod + */ + public String getVoiceFallbackMethod() { + return voiceFallbackMethod; + } + + /** + * @param voiceFallbackMethod the voiceFallbackMethod to set + */ + public void setVoiceFallbackMethod(String voiceFallbackMethod) { + this.voiceFallbackMethod = voiceFallbackMethod; + } + + /** + * @return the statusCallback + */ + public URI getStatusCallback() { + return statusCallback; + } + + /** + * @param statusCallback the statusCallback to set + */ + public void setStatusCallback(URI statusCallback) { + this.statusCallback = statusCallback; + } + + /** + * @return the statusCallbackMethod + */ + public String getStatusCallbackMethod() { + return statusCallbackMethod; + } + + /** + * @param statusCallbackMethod the statusCallbackMethod to set + */ + public void setStatusCallbackMethod(String statusCallbackMethod) { + this.statusCallbackMethod = statusCallbackMethod; + } + + /** + * @return the voiceApplicationSid + */ + public Sid getVoiceApplicationSid() { + return voiceApplicationSid; + } + + /** + * @param voiceApplicationSid the voiceApplicationSid to set + */ + public void setVoiceApplicationSid(Sid voiceApplicationSid) { + this.voiceApplicationSid = voiceApplicationSid; + } + + /** + * @return the smsUrl + */ + public URI getSmsUrl() { + return smsUrl; + } + + /** + * @param smsUrl the smsUrl to set + */ + public void setSmsUrl(URI smsUrl) { + this.smsUrl = smsUrl; + } + + /** + * @return the smsMethod + */ + public String getSmsMethod() { + return smsMethod; + } + + /** + * @param smsMethod the smsMethod to set + */ + public void setSmsMethod(String smsMethod) { + this.smsMethod = smsMethod; + } + + /** + * @return the smsFallbackUrl + */ + public URI getSmsFallbackUrl() { + return smsFallbackUrl; + } + + /** + * @param smsFallbackUrl the smsFallbackUrl to set + */ + public void setSmsFallbackUrl(URI smsFallbackUrl) { + this.smsFallbackUrl = smsFallbackUrl; + } + + /** + * @return the smsFallbackMethod + */ + public String getSmsFallbackMethod() { + return smsFallbackMethod; + } + + /** + * @param smsFallbackMethod the smsFallbackMethod to set + */ + public void setSmsFallbackMethod(String smsFallbackMethod) { + this.smsFallbackMethod = smsFallbackMethod; + } + + /** + * @return the smsApplicationSid + */ + public Sid getSmsApplicationSid() { + return smsApplicationSid; + } + + /** + * @param smsApplicationSid the smsApplicationSid to set + */ + public void setSmsApplicationSid(Sid smsApplicationSid) { + this.smsApplicationSid = smsApplicationSid; + } + + /** + * @return the uri + */ + public URI getUri() { + return uri; + } + + /** + * @param uri the uri to set + */ + public void setUri(URI uri) { + this.uri = uri; + } + + /** + * @return the ussdUrl + */ + public URI getUssdUrl() { + return ussdUrl; + } + + /** + * @param ussdUrl the ussdUrl to set + */ + public void setUssdUrl(URI ussdUrl) { + this.ussdUrl = ussdUrl; + } + + /** + * @return the ussdMethod + */ + public String getUssdMethod() { + return ussdMethod; + } + + /** + * @param ussdMethod the ussdMethod to set + */ + public void setUssdMethod(String ussdMethod) { + this.ussdMethod = ussdMethod; + } + + /** + * @return the ussdFallbackUrl + */ + public URI getUssdFallbackUrl() { + return ussdFallbackUrl; + } + + /** + * @param ussdFallbackUrl the ussdFallbackUrl to set + */ + public void setUssdFallbackUrl(URI ussdFallbackUrl) { + this.ussdFallbackUrl = ussdFallbackUrl; + } + + /** + * @return the ussdFallbackMethod + */ + public String getUssdFallbackMethod() { + return ussdFallbackMethod; + } + + /** + * @param ussdFallbackMethod the ussdFallbackMethod to set + */ + public void setUssdFallbackMethod(String ussdFallbackMethod) { + this.ussdFallbackMethod = ussdFallbackMethod; + } + + /** + * @return the ussdApplicationSid + */ + public Sid getUssdApplicationSid() { + return ussdApplicationSid; + } + + /** + * @param ussdApplicationSid the ussdApplicationSid to set + */ + public void setUssdApplicationSid(Sid ussdApplicationSid) { + this.ussdApplicationSid = ussdApplicationSid; + } + + /** + * @return the referUrl + */ + public URI getReferUrl() { + return referUrl; + } + + /** + * @param referUrl the referUrl to set + */ + public void setReferUrl(URI referUrl) { + this.referUrl = referUrl; + } + + /** + * @return the referMethod + */ + public String getReferMethod() { + return referMethod; + } + + /** + * @param referMethod the referMethod to set + */ + public void setReferMethod(String referMethod) { + this.referMethod = referMethod; + } + + /** + * @return the referApplicationSid + */ + public Sid getReferApplicationSid() { + return referApplicationSid; + } + + /** + * @param referApplicationSid the referApplicationSid to set + */ + public void setReferApplicationSid(Sid referApplicationSid) { + this.referApplicationSid = referApplicationSid; + } + + /** + * @return the referApplicationName + */ + public String getReferApplicationName() { + return referApplicationName; + } + + /** + * @param referApplicationName the referApplicationName to set + */ + public void setReferApplicationName(String referApplicationName) { + this.referApplicationName = referApplicationName; + } + + /** + * @return the voiceCapable + */ + public Boolean isVoiceCapable() { + return voiceCapable; + } + + /** + * @param voiceCapable the voiceCapable to set + */ + public void setVoiceCapable(Boolean voiceCapable) { + this.voiceCapable = voiceCapable; + } + + /** + * @return the smsCapable + */ + public Boolean isSmsCapable() { + return smsCapable; + } + + /** + * @param smsCapable the smsCapable to set + */ + public void setSmsCapable(Boolean smsCapable) { + this.smsCapable = smsCapable; + } + + /** + * @return the mmsCapable + */ + public Boolean isMmsCapable() { + return mmsCapable; + } + + /** + * @param mmsCapable the mmsCapable to set + */ + public void setMmsCapable(Boolean mmsCapable) { + this.mmsCapable = mmsCapable; + } + + /** + * @return the faxCapable + */ + public Boolean isFaxCapable() { + return faxCapable; + } + + /** + * @param faxCapable the faxCapable to set + */ + public void setFaxCapable(Boolean faxCapable) { + this.faxCapable = faxCapable; + } + + public Boolean isPureSip() { + return pureSip; + } + + public void setPureSip(Boolean pureSip) { + this.pureSip = pureSip; + } + + public void setVoiceApplicationName(String voiceApplicationName) { + this.voiceApplicationName = voiceApplicationName; + } + + public void setSmsApplicationName(String smsApplicationName) { + this.smsApplicationName = smsApplicationName; + } + + public void setUssdApplicationName(String ussdApplicationName) { + this.ussdApplicationName = ussdApplicationName; + } + + public void setOrganizationSid(Sid organizationSid) { + this.organizationSid = organizationSid; + } + + public String getVoiceApplicationName() { + return voiceApplicationName; + } + + public String getSmsApplicationName() { + return smsApplicationName; + } + + public String getUssdApplicationName() { + return ussdApplicationName; + } + + /** + * @return the organizationSid + */ + public Sid getOrganizationSid() { + return organizationSid; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public String toString() { + return "IncomingPhoneNumber [sid=" + sid + ", friendlyName=" + friendlyName + ", accountSid=" + accountSid + + ", phoneNumber=" + phoneNumber + ", cost=" + cost + ", apiVersion=" + apiVersion + + ", hasVoiceCallerIdLookup=" + hasVoiceCallerIdLookup + ", voiceUrl=" + voiceUrl + ", voiceMethod=" + + voiceMethod + ", voiceFallbackUrl=" + voiceFallbackUrl + ", voiceFallbackMethod=" + + voiceFallbackMethod + ", statusCallback=" + statusCallback + ", statusCallbackMethod=" + + statusCallbackMethod + ", voiceApplicationSid=" + voiceApplicationSid + ", smsUrl=" + smsUrl + + ", smsMethod=" + smsMethod + ", smsFallbackUrl=" + smsFallbackUrl + ", smsFallbackMethod=" + + smsFallbackMethod + ", smsApplicationSid=" + smsApplicationSid + ", uri=" + uri + ", ussdUrl=" + + ussdUrl + ", ussdMethod=" + ussdMethod + ", ussdFallbackUrl=" + ussdFallbackUrl + + ", ussdFallbackMethod=" + ussdFallbackMethod + ", ussdApplicationSid=" + ussdApplicationSid + + ", referUrl=" + referUrl + ", referMethod=" + referMethod + ", referApplicationSid=" + + referApplicationSid + ", voiceCapable=" + voiceCapable + ", smsCapable=" + smsCapable + + ", mmsCapable=" + mmsCapable + ", faxCapable=" + faxCapable + ", pureSip=" + pureSip + + ", organizationSid=" + organizationSid + "]"; + } + + @NotThreadSafe + public static final class Builder { + private Sid sid; + private String friendlyName; + private Sid accountSid; + private String phoneNumber; + private String cost; + private String apiVersion; + private Boolean hasVoiceCallerIdLookup; + private URI voiceUrl; + private String voiceMethod; + private URI voiceFallbackUrl; + private String voiceFallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private Sid voiceApplicationSid; + private URI smsUrl; + private String smsMethod; + private URI smsFallbackUrl; + private String smsFallbackMethod; + private Sid smsApplicationSid; + private URI uri; + + private URI ussdUrl; + private String ussdMethod; + private URI ussdFallbackUrl; + private String ussdFallbackMethod; + private Sid ussdApplicationSid; + + private URI referUrl; + private String referMethod; + private Sid referApplicationSid; + + // Capabilities + private Boolean voiceCapable; + private Boolean smsCapable; + private Boolean mmsCapable; + private Boolean faxCapable; + private Boolean pureSip; + + private Sid organizationSid; + + public Builder() { + super(); + } + + public IncomingPhoneNumber build() { + final DateTime now = DateTime.now(); + return new IncomingPhoneNumber(sid, now, now, friendlyName, accountSid, phoneNumber, cost, apiVersion, + hasVoiceCallerIdLookup, voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, + statusCallbackMethod, voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, + smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, + referUrl, referMethod, referApplicationSid, + voiceCapable, smsCapable, mmsCapable, faxCapable, pureSip, organizationSid); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setFriendlyName(final String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setAccountSid(final Sid accountSid) { + this.accountSid = accountSid; + } + + public void setPhoneNumber(final String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public void setCost(final String cost) { + this.cost = cost; + } + + public void setApiVersion(final String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setHasVoiceCallerIdLookup(final boolean hasVoiceCallerIdLookup) { + this.hasVoiceCallerIdLookup = hasVoiceCallerIdLookup; + } + + public void setVoiceUrl(final URI voiceUrl) { + this.voiceUrl = voiceUrl; + } + + public void setVoiceMethod(final String voiceMethod) { + this.voiceMethod = voiceMethod; + } + + public void setVoiceFallbackUrl(final URI voiceFallbackUrl) { + this.voiceFallbackUrl = voiceFallbackUrl; + } + + public void setVoiceFallbackMethod(final String voiceFallbackMethod) { + this.voiceFallbackMethod = voiceFallbackMethod; + } + + public void setStatusCallback(final URI statusCallback) { + this.statusCallback = statusCallback; + } + + public void setStatusCallbackMethod(final String statusCallbackMethod) { + this.statusCallbackMethod = statusCallbackMethod; + } + + public void setVoiceApplicationSid(final Sid voiceApplicationSid) { + this.voiceApplicationSid = voiceApplicationSid; + } + + public void setSmsUrl(final URI smsUrl) { + this.smsUrl = smsUrl; + } + + public void setSmsMethod(final String smsMethod) { + this.smsMethod = smsMethod; + } + + public void setSmsFallbackUrl(final URI smsFallbackUrl) { + this.smsFallbackUrl = smsFallbackUrl; + } + + public void setSmsFallbackMethod(final String smsFallbackMethod) { + this.smsFallbackMethod = smsFallbackMethod; + } + + public void setSmsApplicationSid(final Sid smsApplicationSid) { + this.smsApplicationSid = smsApplicationSid; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + + public void setUssdUrl(final URI ussdUrl) { + this.ussdUrl = ussdUrl; + } + + public void setUssdMethod(final String ussdMethod) { + this.ussdMethod = ussdMethod; + } + + public void setUssdFallbackUrl(final URI ussdFallbackUrl) { + this.ussdFallbackUrl = ussdFallbackUrl; + } + + public void setUssdFallbackMethod(final String ussdFallbackMethod) { + this.ussdFallbackMethod = ussdFallbackMethod; + } + + public void setUssdApplicationSid(final Sid ussdApplicationSid) { + this.ussdApplicationSid = ussdApplicationSid; + } + + public void setOrganizationSid(final Sid organizationSid) { + this.organizationSid = organizationSid; + } + + public URI getReferUrl() { + return referUrl; + } + + public void setReferUrl(URI referUrl) { + this.referUrl = referUrl; + } + + public String getReferMethod() { + return referMethod; + } + + public void setReferMethod(String referMethod) { + this.referMethod = referMethod; + } + + public Sid getReferApplicationSid() { + return referApplicationSid; + } + + public Sid getOrganizationSid() { + return organizationSid; + } + + public void setReferApplicationSid(Sid referApplicationSid) { + this.referApplicationSid = referApplicationSid; + } + + public void setVoiceCapable(Boolean voiceCapable) { + this.voiceCapable = voiceCapable; + } + + public void setSmsCapable(Boolean smsCapable) { + this.smsCapable = smsCapable; + } + + public void setMmsCapable(Boolean mmsCapable) { + this.mmsCapable = mmsCapable; + } + + public void setFaxCapable(Boolean faxCapable) { + this.faxCapable = faxCapable; + } + + public void setPureSip(Boolean pureSip) { + this.pureSip = pureSip; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public String toString() { + return "Builder [sid=" + sid + ", friendlyName=" + friendlyName + ", accountSid=" + accountSid + + ", phoneNumber=" + phoneNumber + ", cost=" + cost + ", apiVersion=" + apiVersion + + ", hasVoiceCallerIdLookup=" + hasVoiceCallerIdLookup + ", voiceUrl=" + voiceUrl + ", voiceMethod=" + + voiceMethod + ", voiceFallbackUrl=" + voiceFallbackUrl + ", voiceFallbackMethod=" + + voiceFallbackMethod + ", statusCallback=" + statusCallback + ", statusCallbackMethod=" + + statusCallbackMethod + ", voiceApplicationSid=" + voiceApplicationSid + ", smsUrl=" + smsUrl + + ", smsMethod=" + smsMethod + ", smsFallbackUrl=" + smsFallbackUrl + ", smsFallbackMethod=" + + smsFallbackMethod + ", smsApplicationSid=" + smsApplicationSid + ", uri=" + uri + ", ussdUrl=" + + ussdUrl + ", ussdMethod=" + ussdMethod + ", ussdFallbackUrl=" + ussdFallbackUrl + + ", ussdFallbackMethod=" + ussdFallbackMethod + ", ussdApplicationSid=" + ussdApplicationSid + + ", referUrl=" + referUrl + ", referMethod=" + referMethod + ", referApplicationSid=" + + referApplicationSid + ", voiceCapable=" + voiceCapable + ", smsCapable=" + smsCapable + + ", mmsCapable=" + mmsCapable + ", faxCapable=" + faxCapable + ", pureSip=" + pureSip + + ", organizationSid=" + organizationSid + "]"; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberFilter.java new file mode 100644 index 0000000000..b8828c2e66 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberFilter.java @@ -0,0 +1,225 @@ +/* + * 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.dao.entities; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author Jean Deruelle + */ +@Immutable +public class IncomingPhoneNumberFilter { + + private final String accountSid; + private final String friendlyName; + private final String phoneNumber; + private final String sortBy; + private final String sortDirection; + private final Integer limit; + private final Integer offset; + private final String orgSid; + private final Boolean pureSIP; + private SearchFilterMode filterMode; + + private IncomingPhoneNumberFilter(String accountSid, String friendlyName, String phoneNumber, String sortBy, + String sortDirection, Integer limit, Integer offset, String orgSid, Boolean pureSIP, SearchFilterMode filterMode) { + this.accountSid = accountSid; + this.friendlyName = friendlyName; + this.phoneNumber = phoneNumber; + this.sortBy = sortBy; + this.sortDirection = sortDirection; + this.limit = limit; + this.offset = offset; + this.orgSid = orgSid; + this.pureSIP = pureSIP; + this.filterMode = filterMode; + } + + public IncomingPhoneNumberFilter(String accountSid, String friendlyName, String phoneNumber) { + this.accountSid = accountSid; + this.friendlyName = friendlyName; + this.phoneNumber = phoneNumber; + this.sortBy = null; + this.sortDirection = null; + this.offset = null; + this.limit = null; + this.orgSid = null; + this.pureSIP = null; + this.filterMode = SearchFilterMode.PERFECT_MATCH; + } + + public String getAccountSid() { + return accountSid; + } + + /** + * @return the friendlyName + */ + public String getFriendlyName() { + return friendlyName; + } + + /** + * @return the phoneNumber + */ + public String getPhoneNumber() { + return phoneNumber; + } + + /** + * @return the sortBy + */ + public String getSortBy() { + return sortBy; + } + + /** + * @return the sortDirection + */ + public String getSortDirection() { + return sortDirection; + } + + /** + * @return the limit + */ + public Integer getLimit() { + return limit; + } + + /** + * @return the offset + */ + public Integer getOffset() { + return offset; + } + + public String getOrgSid() { + return orgSid; + } + + public Boolean getPureSIP() { + return pureSIP; + } + + public SearchFilterMode getFilterMode() { + return filterMode; + } + + @Override + public String toString() { + return "IncomingPhoneNumberFilter{" + "accountSid=" + accountSid + ", friendlyName=" + friendlyName + ", phoneNumber=" + phoneNumber + ", sortBy=" + sortBy + ", sortDirection=" + sortDirection + ", limit=" + limit + ", offset=" + offset + ", orgSid=" + orgSid + ", pureSIP=" + pureSIP + '}'; + } + + public static final class Builder { + + private String accountSid = null; + private String friendlyName = null; + private String phoneNumber = null; + private String sortBy = null; + private String sortDirection = null; + private Integer limit = null; + private Integer offset = null; + private String orgSid = null; + private Boolean pureSIP = null; + private SearchFilterMode filterMode = SearchFilterMode.PERFECT_MATCH; + + public static IncomingPhoneNumberFilter.Builder builder() { + return new IncomingPhoneNumberFilter.Builder(); + } + + /** + * Prepare fields with SQL wildcards + * + * @param value + * @return + */ + private String convertIntoSQLWildcard(String value) { + String wildcarded = value; + // The LIKE keyword uses '%' to match any (including 0) number of characters, and '_' to match exactly one character + // Add here the '%' keyword so +15126002188 will be the same as 15126002188 and 6002188 + if (wildcarded != null) { + wildcarded = "%" + wildcarded + "%"; + } + return wildcarded; + } + + public IncomingPhoneNumberFilter build() { + if (filterMode.equals(SearchFilterMode.WILDCARD_MATCH)) { + phoneNumber = convertIntoSQLWildcard(phoneNumber); + friendlyName = convertIntoSQLWildcard(friendlyName); + } + + return new IncomingPhoneNumberFilter(accountSid, + friendlyName, + phoneNumber, + sortBy, + sortDirection, + limit, + offset, + orgSid, + pureSIP, + filterMode); + } + + public Builder byAccountSid(String accountSid) { + this.accountSid = accountSid; + return this; + } + + public Builder byPureSIP(Boolean pureSIP) { + this.pureSIP = pureSIP; + return this; + } + + public Builder byFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + public Builder byPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + return this; + } + + public Builder sortedBy(String sortBy, String sortDirection) { + this.sortBy = sortBy; + this.sortDirection = sortDirection; + return this; + } + + public Builder usingMode(SearchFilterMode mode) { + this.filterMode = mode; + return this; + } + + public Builder limited(Integer limit, Integer offset) { + this.limit = limit; + this.offset = offset; + return this; + } + + public Builder byOrgSid(String orgSid) { + this.orgSid = orgSid; + return this; + } + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberList.java similarity index 91% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberList.java index c42f3efb72..01cc7587fd 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/IncomingPhoneNumberList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/IncomingPhoneNumberList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/InstanceId.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/InstanceId.java new file mode 100644 index 0000000000..eecdc64fb0 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/InstanceId.java @@ -0,0 +1,66 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.dao.entities; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author gvagenas + * + */ +public class InstanceId { + + private Sid instanceId; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final String host; + + public InstanceId(final Sid instanceId, final String host, final DateTime dateCreated, final DateTime dateUpdated) { + this.instanceId = instanceId; + this.host = host; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + } + + public Sid getId() { + return instanceId; + } + + public String getHost() { return host; } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public InstanceId setInstanceId(final Sid instanceId, final String host) { + return new InstanceId(instanceId, host, this.dateCreated, DateTime.now()); + } + + @Override + public String toString() { + return this.instanceId+"/"+this.host; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaAttributes.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaAttributes.java new file mode 100644 index 0000000000..637a18e8b1 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaAttributes.java @@ -0,0 +1,211 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2017, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao.entities; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * Gathers media attributes that are used to create a media session. + * + * @author guilherme.jansen@telestax.com + */ +@Immutable +public class MediaAttributes { + + private final MediaType mediaType; + // video attributes + private final VideoMode videoMode; + private final VideoResolution videoResolution; + private final VideoLayout videoLayout; + private final String videoOverlay; + + /** + * Constructor for audio-only media sessions + */ + public MediaAttributes() { + this.mediaType = MediaType.AUDIO_ONLY; + this.videoMode = null; + this.videoResolution = null; + this.videoLayout = null; + this.videoOverlay = null; + } + + /** + * Constructor for audio-video or video-only media sessions (conference calls) + * + * @param mediaType + * @param videoMode + * @param videoResolution + * @param videoLayout + * @param videoOverlay + */ + public MediaAttributes(final MediaType mediaType, final VideoMode videoMode, final VideoResolution videoResolution, + final VideoLayout videoLayout, final String videoOverlay) { + if (MediaType.AUDIO_ONLY.equals(mediaType)) { + throw new IllegalArgumentException("Informed mediaType is not compatible with video."); + } + this.mediaType = mediaType; + this.videoMode = videoMode; + this.videoResolution = videoResolution; + this.videoLayout = videoLayout; + this.videoOverlay = videoOverlay; + } + + /** + * Constructor for audio-video or video-only media sessions (outbound calls / fork) + * + * @param mediaType + * @param videoResolution + */ + public MediaAttributes(final MediaType mediaType, final VideoResolution videoResolution){ + this(mediaType, null, videoResolution, null, null); + } + + public MediaType getMediaType() { + return mediaType; + } + + public VideoMode getVideoMode() { + return videoMode; + } + + public VideoResolution getVideoResolution() { + return videoResolution; + } + + public VideoLayout getVideoLayout() { + return videoLayout; + } + + public String getVideoOverlay() { + return videoOverlay; + } + + public enum MediaType { + AUDIO_ONLY("audio_only", new String[] {"audio"}), + VIDEO_ONLY("video_only", new String[] {"video"}), + AUDIO_VIDEO("audio_video", new String[] {"audio", "video"}); + + private final String text; + private final String[] codecPolicy; + + MediaType(final String text, final String[] codecPolicy) { + this.text = text; + this.codecPolicy = codecPolicy; + } + + public static MediaType getValueOf(final String text) { + MediaType[] values = values(); + for (final MediaType value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid media type."); + } + + @Override + public String toString() { + return text; + } + + public String[] getCodecPolicy() { + return codecPolicy; + } + } + + public enum VideoMode { + MCU("mcu"), SFU("sfu"); + + final String text; + + VideoMode(final String text) { + this.text = text; + } + + public static VideoMode getValueOf(final String text) { + VideoMode[] values = values(); + for (final VideoMode value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid video mode."); + } + + @Override + public String toString() { + return this.text; + } + } + + public enum VideoResolution { + CIF("CIF"), FOUR_CIF("4CIF"), SIXTEEN_CIF("16CIF"), QCIF("QCIF"), VGA("VGA"), SEVEN_TWENTY_P("720p"); + + final String text; + + VideoResolution(final String text) { + this.text = text; + } + + public static VideoResolution getValueOf(final String text) { + VideoResolution[] values = values(); + for (final VideoResolution value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid video resolution."); + } + + @Override + public String toString() { + return this.text; + } + } + + public enum VideoLayout { + LINEAR("linear"), TILE("tile"); + + final String text; + + VideoLayout(final String text) { + this.text = text; + } + + public static VideoLayout getValueOf(final String text) { + VideoLayout[] values = values(); + for (final VideoLayout value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid video layout."); + } + + @Override + public String toString() { + return this.text; + } + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntity.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntity.java new file mode 100644 index 0000000000..8ef6305d8f --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntity.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.dao.entities; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@Immutable +public final class MediaResourceBrokerEntity { + private final Sid conferenceSid; + private String slaveMsId; + private String slaveMsBridgeEpId; + private String slaveMsCnfEpId; + private boolean isBridgedTogether; + + public MediaResourceBrokerEntity(final Sid conferenceSid, final String slaveMsId, final String slaveMsBridgeEpId, + final String slaveMsCnfEpId, final Boolean isBridgedTogether) { + super(); + this.conferenceSid = conferenceSid; + this.slaveMsId = slaveMsId; + this.slaveMsBridgeEpId = slaveMsBridgeEpId; + this.slaveMsCnfEpId = slaveMsCnfEpId; + this.isBridgedTogether = isBridgedTogether; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getConferenceSid() { + return conferenceSid; + } + + public String getSlaveMsId() { + return slaveMsId; + } + + public String getSlaveMsBridgeEpId() { + return slaveMsBridgeEpId; + } + + public String getSlaveMsCnfEpId() { + return slaveMsCnfEpId; + } + + public boolean isBridgedTogether() { + return isBridgedTogether; + } + + @NotThreadSafe + public static final class Builder { + private Sid conferenceSid; + private String slaveMsId; + private String slaveMsBridgeEpId; + private String slaveMsCnfEpId; + private boolean isBridgedTogether; + + private Builder() { + super(); + conferenceSid = null; + slaveMsId = null; + slaveMsBridgeEpId = null; + slaveMsCnfEpId = null; + } + + public MediaResourceBrokerEntity build() { + return new MediaResourceBrokerEntity(conferenceSid, slaveMsId, slaveMsBridgeEpId, slaveMsCnfEpId, isBridgedTogether); + } + + public void setConferenceSid(Sid conferenceSid) { + this.conferenceSid = conferenceSid; + } + + public void setSlaveMsId(String slaveMsId) { + this.slaveMsId = slaveMsId; + } + + public void setSlaveMsBridgeEpId(String slaveMsBridgeEpId) { + this.slaveMsBridgeEpId = slaveMsBridgeEpId; + } + + public void setSlaveMsCnfEpId(String slaveMsCnfEpId) { + this.slaveMsCnfEpId = slaveMsCnfEpId; + } + + public void setBridgedTogether(boolean isBridgedTogether) { + this.isBridgedTogether = isBridgedTogether; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntityFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntityFilter.java new file mode 100644 index 0000000000..5b9a7cbd83 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaResourceBrokerEntityFilter.java @@ -0,0 +1,46 @@ +/* + * 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.dao.entities; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ + +@Immutable +public class MediaResourceBrokerEntityFilter { + + private final String conferenceSid; + private String slaveMsId; + + public MediaResourceBrokerEntityFilter(String conferenceSid, String slaveMsId) { + this.conferenceSid = conferenceSid; + this.slaveMsId = slaveMsId; + } + + public String getConferenceSid() { + return conferenceSid; + } + + public String getSlaveMsId() { + return slaveMsId; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerEntity.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerEntity.java new file mode 100644 index 0000000000..9428955ed4 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerEntity.java @@ -0,0 +1,148 @@ +/* + * 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.dao.entities; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@Immutable +public final class MediaServerEntity { + private final int msId; + private final String compatibility; + private final String localIpAddress; + private final int localPort; + private final String remoteIpAddress; + private final int remotePort; + private final String responseTimeout; + private final String externalAddress; + + public MediaServerEntity(final int msId, final String compatibility,final String localIpAddress, final int localPort, + final String remoteIpAddress, final int remotePort, final String responseTimeout, final String externalAddress) { + super(); + this.msId = msId; + this.compatibility = compatibility; + this.localIpAddress = localIpAddress; + this.localPort = localPort; + this.remoteIpAddress = remoteIpAddress; + this.remotePort = remotePort; + this.responseTimeout = responseTimeout; + this.externalAddress = externalAddress; + } + + public static Builder builder() { + return new Builder(); + } + + public int getMsId() { + return this.msId; + } + + public String getCompatibility() { + return this.compatibility; + } + + public String getLocalIpAddress() { + return this.localIpAddress; + } + + public int getLocalPort() { + return this.localPort; + } + + public String getRemoteIpAddress() { + return this.remoteIpAddress; + } + + public int getRemotePort() { + return this.remotePort; + } + + public String getResponseTimeout() { + return this.responseTimeout; + } + + public String getExternalAddress() { + return this.externalAddress; + } + + public MediaServerEntity setMsId(int msId) { + return new MediaServerEntity(msId, compatibility, localIpAddress, localPort, remoteIpAddress, remotePort, responseTimeout, externalAddress); + } + + @NotThreadSafe + public static final class Builder { + private int msId; + private String compatibility; + private String localIpAddress; + private int localPort; + private String remoteIpAddress; + private int remotePort; + private String responseTimeout; + private String externalAddress; + + private Builder() { + super(); + compatibility = null; + localIpAddress = null; + remoteIpAddress = null; + responseTimeout = null; + externalAddress = null; + } + + public MediaServerEntity build() { + return new MediaServerEntity(msId, compatibility, localIpAddress, localPort, remoteIpAddress, remotePort, responseTimeout, externalAddress); + } + + public void setMsId(int msId) { + this.msId = msId; + } + + public void setCompatibility(String compatibility) { + this.compatibility = compatibility; + } + + public void setLocalIpAddress(String localIpAddress) { + this.localIpAddress = localIpAddress; + } + + public void setLocalPort(int localPort) { + this.localPort = localPort; + } + + public void setRemoteIpAddress(String remoteIpAddress) { + this.remoteIpAddress = remoteIpAddress; + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public void setResponseTimeout(String responseTimeout) { + this.responseTimeout = responseTimeout; + } + + public void setExternalAddress(String externalAddress) { + this.externalAddress = externalAddress; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerFilter.java new file mode 100644 index 0000000000..0c2009c643 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MediaServerFilter.java @@ -0,0 +1,49 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ + +@Immutable +public class MediaServerFilter { + + private final String msIpAddress; + private final String msPort; + + public MediaServerFilter(final String msIpAddress, final String msPort) throws ParseException { + this.msIpAddress = msIpAddress; + this.msPort = msPort; + } + + public String getMsIpAddress() { + return msIpAddress; + } + + public String getMsPort() { + return msPort; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MostOptimalNumberResponse.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MostOptimalNumberResponse.java new file mode 100644 index 0000000000..61f1dafe17 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/MostOptimalNumberResponse.java @@ -0,0 +1,49 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.dao.entities; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public class MostOptimalNumberResponse { + + private final IncomingPhoneNumber number; + private final boolean relevant; + + /** + * @param number - number from db + * @param relevant - if this number belongs to proper organization as per restrictions or not + */ + public MostOptimalNumberResponse(IncomingPhoneNumber number, boolean relevant) { + super(); + this.number = number; + this.relevant = relevant; + } + + public IncomingPhoneNumber number() { + return number; + } + + /** + * @return true if number belongs to proper organization as per restrictions, or false otherwise + */ + public boolean isRelevant() { + return relevant; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Notification.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Notification.java similarity index 96% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Notification.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Notification.java index 19782a8026..f1e0453caf 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Notification.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Notification.java @@ -17,14 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationFilter.java new file mode 100644 index 0000000000..c706a178de --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationFilter.java @@ -0,0 +1,120 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author vunguyen + */ + +@Immutable +public class NotificationFilter { + + private final String accountSid; + private final List accountSidSet; // if not-null we need the cdrs that belong to several accounts + private final Date startTime; // to initialize it pass string arguments with yyyy-MM-dd format + private final Date endTime; + private final String errorCode; + private final String requestUrl; + private final String messageText; + private final Integer limit; + private final Integer offset; + private final String instanceid; + + public NotificationFilter(String accountSid, List accountSidSet, String startTime, String endTime, String errorCode, String requestUrl, + String messageText, Integer limit, Integer offset) throws ParseException { + this(accountSid, accountSidSet, startTime,endTime, errorCode, requestUrl, messageText, limit,offset,null); + } + + public NotificationFilter(String accountSid, List accountSidSet, String startTime, String endTime, String errorCode, String requestUrl, + String messageText, Integer limit, Integer offset, String instanceId) throws ParseException { + this.accountSid = accountSid; + this.accountSidSet = accountSidSet; + + this.errorCode = errorCode; + this.requestUrl = requestUrl; + this.messageText = messageText; + this.limit = limit; + this.offset = offset; + if (startTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(startTime); + this.startTime = date; + } else + this.startTime = null; + + if (endTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(endTime); + this.endTime = date; + } else { + this.endTime = null; + } + if (instanceId != null && !instanceId.isEmpty()) { + this.instanceid = instanceId; + } else { + this.instanceid = null; + } + } + + public String getSid() { + return accountSid; + } + + public List getAccountSidSet() { + return accountSidSet; + } + + public String getErrorCode() { + return errorCode; + } + + public String getRequestUrl() { + return requestUrl; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public String getMessageText() { + return messageText; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getInstanceid() { return instanceid; } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/NotificationList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/NotificationList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationList.java index 067c62bec3..caddd6f2dc 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/NotificationList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/NotificationList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Organization.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Organization.java new file mode 100644 index 0000000000..6d68b314b1 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Organization.java @@ -0,0 +1,173 @@ +/* + * 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.dao.entities; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@Immutable +public final class Organization { + private final Sid sid; + private final String domainName; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final Status status; + + /** + * @param sid + * @param domainName - such as customer.restcomm.com + * @param dateCreated + * @param dateUpdated + * @param Status + * @throws IllegalArgumentException if sid or domainName are null/empty + */ + public Organization(final Sid sid, final String domainName, final DateTime dateCreated, final DateTime dateUpdated, final Status status) throws IllegalArgumentException { + super(); + if(domainName == null || domainName.trim().isEmpty()) + throw new IllegalArgumentException("Organization domainName can not be empty."); + if(sid == null) + throw new IllegalArgumentException("Organization sid can not be empty."); + this.sid = sid; + + if(domainName.endsWith(".")){ + this.domainName = domainName.substring(0, domainName.lastIndexOf('.')); + }else{ + this.domainName = domainName; + } + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.status = status; + } + + public enum Status { + // max length of a new status should be under 16 characters otherwise schema update is required. + ACTIVE("active"), CLOSED("closed"); + + private final String text; + + private Status(final String text) { + this.text = text; + } + + public static Status getValueOf(final String text) { + Status[] values = values(); + for (final Status value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid organization status."); + } + + @Override + public String toString() { + return text; + } + }; + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public String getDomainName() { + if(domainName != null && domainName.endsWith(".")) + return domainName.substring(0, domainName.lastIndexOf('.')); + return domainName; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public Status getStatus() { + return status; + } + + /** + * @param domainName + * @return + * @throws IllegalArgumentException in case provided domainName is empty or null + */ + public Organization setDomainName(final String domainName) throws IllegalArgumentException { + if(domainName == null || domainName.trim().isEmpty()) + throw new IllegalArgumentException("Organization domainName can not be empty."); + return new Organization(sid, domainName, dateCreated, DateTime.now(), status); + } + + @NotThreadSafe + public static final class Builder { + private Sid sid; + private String domainName; + private DateTime dateCreated; + private DateTime dateUpdated; + private Status status; + + private Builder() { + super(); + sid = null; + domainName = null; + dateCreated = DateTime.now(); + dateUpdated = DateTime.now(); + status = null; + } + + public Organization build() { + return new Organization(sid, domainName, dateCreated, dateUpdated, status); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setDomainName(final String domainName) { + this.domainName = domainName; + } + + public void setStatus(final Status status) { + this.status = status; + } + + @Override + public String toString() { + return "Organization.Builder [sid=" + sid + ", domainName=" + domainName + ", dateCreated=" + dateCreated + + ", dateUpdated=" + dateUpdated + ", status=" + status + "]"; + } + } + + @Override + public String toString() { + return "Organization [sid=" + sid + ", domainName=" + domainName + ", dateCreated=" + dateCreated + + ", dateUpdated=" + dateUpdated + ", status=" + status + "]"; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OrganizationList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OrganizationList.java new file mode 100644 index 0000000000..c945849607 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OrganizationList.java @@ -0,0 +1,44 @@ +/* + * 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.dao.entities; + +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author maria farooq + */ +@NotThreadSafe +public final class OrganizationList { + private final List organizations; + + public OrganizationList(final List organizations) { + super(); + this.organizations = organizations; + } + + /** + * @return list of organization + */ + public List getOrganizations() { + return organizations; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerId.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerId.java similarity index 93% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerId.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerId.java index 4e84ea5368..23a59b6bad 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerId.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerId.java @@ -17,13 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerIdList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerIdList.java similarity index 91% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerIdList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerIdList.java index 647d6b4d6f..966e534f4d 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/OutgoingCallerIdList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/OutgoingCallerIdList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Profile.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Profile.java new file mode 100644 index 0000000000..1115a8e2df --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Profile.java @@ -0,0 +1,101 @@ +/* + * 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.dao.entities; + +import java.util.Calendar; +import java.util.Date; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@Immutable +public final class Profile{ + public static final String DEFAULT_PROFILE_SID = "PRae6e420f425248d6a26948c17a9e2acf"; + private final String sid; + private final String profileDocument; + private final Date dateCreated; + private final Date dateUpdated; + + public Profile(final String sid, final String profileDocument, final Date dateCreated, final Date dateUpdated) { + super(); + this.sid = sid; + this.profileDocument = profileDocument; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + } + + public static Builder builder() { + return new Builder(); + } + + public String getSid() { + return sid; + } + + public String getProfileDocument() { + return profileDocument; + } + + public Date getDateCreated() { + return dateCreated; + } + + public Date getDateUpdated() { + return dateUpdated; + } + + public Profile setProfileDocument(String updatedProfileDocument){ + return new Profile(this.sid, updatedProfileDocument, this.dateCreated, this.dateUpdated); + } + + @NotThreadSafe + public static final class Builder { + private String sid; + private String profileDocument; + private Date dateCreated; + + private Builder() { + super(); + sid = null; + profileDocument = null; + dateCreated = null; + } + + public Profile build() { + return new Profile(sid, profileDocument, dateCreated, Calendar.getInstance().getTime()); + } + + public void setProfileDocument(final String profileDocument) { + this.profileDocument = profileDocument; + } + + public void setSid(final String sid) { + this.sid = sid; + } + + public void setDateCreated(final Date dateCreated) { + this.dateCreated = dateCreated; + } + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ProfileAssociation.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ProfileAssociation.java new file mode 100644 index 0000000000..92a2b01720 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ProfileAssociation.java @@ -0,0 +1,115 @@ +/* + * 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.dao.entities; + +import java.util.Calendar; +import java.util.Date; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@Immutable +public final class ProfileAssociation{ + private final Sid profileSid; + private final Sid targetSid; + private final Date dateCreated; + private final Date dateUpdated; + + /** + * @param profileSid + * @param targetSid can be account or organizaation Sid + * @param dateCreated + * @param dateUpdated + */ + public ProfileAssociation(final Sid profileSid, final Sid targetSid, final Date dateCreated, final Date dateUpdated) { + super(); + this.profileSid = profileSid; + this.targetSid = targetSid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getProfileSid() { + return profileSid; + } + + public Sid getTargetSid() { + return targetSid; + } + + public Date getDateCreated() { + return dateCreated; + } + + public Date getDateUpdated() { + return dateUpdated; + } + + /** + * @param newProfileSid + * @return + */ + public ProfileAssociation setProfileSid(final Sid newProfileSid){ + return new ProfileAssociation(newProfileSid, targetSid, dateCreated, Calendar.getInstance().getTime()); + } + @NotThreadSafe + public static final class Builder { + private Sid profileSid; + private Sid targetSid; + private Date dateCreated; + + private Builder() { + super(); + profileSid = null; + targetSid = null; + dateCreated = null; + } + + public ProfileAssociation build() { + return new ProfileAssociation(profileSid, targetSid, dateCreated, Calendar.getInstance().getTime()); + } + + public void setProfileDocument(final Sid targetSid) { + this.targetSid = targetSid; + } + + public void setSid(final Sid profileSid) { + this.profileSid = profileSid; + } + + public void setDateCreated(final Date dateCreated) { + this.dateCreated = dateCreated; + } + } + + @Override + public String toString() { + return "ProfileAssociation [profileSid=" + profileSid + ", targetSid=" + targetSid + ", dateCreated=" + + dateCreated + ", dateUpdated=" + dateUpdated + "]"; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Recording.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Recording.java new file mode 100644 index 0000000000..a7ddc6f4e0 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Recording.java @@ -0,0 +1,170 @@ +/* + * 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.dao.entities; + +import java.net.URI; + +import org.joda.time.DateTime; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public final class Recording { + private final Sid sid; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final Sid accountSid; + private final Sid callSid; + private final Double duration; + private final String apiVersion; + private URI uri; + private URI fileUri; + private URI s3Uri; + + public Recording(final Sid sid, final DateTime dateCreated, final DateTime dateUpdated, final Sid accountSid, + final Sid callSid, final Double duration, final String apiVersion, final URI uri, final URI fileUri, final URI s3Uri) { + super(); + this.sid = sid; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.accountSid = accountSid; + this.callSid = callSid; + this.duration = duration; + this.apiVersion = apiVersion; + this.uri = uri; + this.fileUri = fileUri; + this.s3Uri = s3Uri; + } + + public static Builder builder() { + return new Builder(); + } + + public Sid getSid() { + return sid; + } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public Sid getAccountSid() { + return accountSid; + } + + public Sid getCallSid() { + return callSid; + } + + public Double getDuration() { + return duration; + } + + public String getApiVersion() { + return apiVersion; + } + + public URI getUri() { + return uri; + } + + public Recording updateUri(URI newUri) { + this.uri = newUri; + return this; + } + + public URI getFileUri() { + return fileUri; + } + + public Recording updateFileUri(URI newFileUri) { + this.fileUri = newFileUri; + return this; + } + + public Recording setS3Uri(URI s3Uri) { + this.s3Uri = s3Uri; + return this; + } + + public URI getS3Uri() { + return s3Uri; + } + + @NotThreadSafe + public static final class Builder { + private Sid sid; + private Sid accountSid; + private Sid callSid; + private Double duration; + private String apiVersion; + private URI uri; + private URI fileUri; + private URI s3Uri; + + private Builder() { + super(); + } + + public Recording build() { + final DateTime now = DateTime.now(); + return new Recording(sid, now, now, accountSid, callSid, duration, apiVersion, uri, fileUri, s3Uri); + } + + public void setSid(final Sid sid) { + this.sid = sid; + } + + public void setAccountSid(final Sid accountSid) { + this.accountSid = accountSid; + } + + public void setCallSid(final Sid callSid) { + this.callSid = callSid; + } + + public void setDuration(final double duration) { + this.duration = duration; + } + + public void setApiVersion(final String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setUri(final URI uri) { + this.uri = uri; + } + + public void setFileUri(final URI uri) { + this.fileUri = fileUri; + } + + public void setS3Uri(final URI s3Uri) { this.s3Uri = s3Uri; } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingFilter.java new file mode 100644 index 0000000000..64bc4b3e16 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingFilter.java @@ -0,0 +1,106 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * @author vunguyen + */ + +public class RecordingFilter { + + private final String accountSid; + private final List accountSidSet; // if not-null we need the cdrs that belong to several accounts + private final Date startTime; // to initialize it pass string arguments with yyyy-MM-dd format + private final Date endTime; + private final String callSid; + private final Integer limit; + private final Integer offset; + private final String instanceid; + + public RecordingFilter(String accountSid, List accountSidSet, String startTime, String endTime, + String callSid, Integer limit, Integer offset) throws ParseException { + this(accountSid, accountSidSet, startTime,endTime, callSid, limit,offset,null); + } + + public RecordingFilter(String accountSid, List accountSidSet, String startTime, String endTime, + String callSid, Integer limit, Integer offset, String instanceId) throws ParseException { + this.accountSid = accountSid; + this.accountSidSet = accountSidSet; + + this.callSid = callSid; + this.limit = limit; + this.offset = offset; + if (startTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(startTime); + this.startTime = date; + } else + this.startTime = null; + + if (endTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(endTime); + this.endTime = date; + } else { + this.endTime = null; + } + if (instanceId != null && !instanceId.isEmpty()) { + this.instanceid = instanceId; + } else { + this.instanceid = null; + } + } + + public String getSid() { + return accountSid; + } + + public List getAccountSidSet() { + return accountSidSet; + } + + public String getCallSid() { + return callSid; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getInstanceid() { return instanceid; } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RecordingList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RecordingList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingList.java index 83da4a7626..20d89bf77a 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RecordingList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RecordingList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Registration.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Registration.java new file mode 100644 index 0000000000..3c28fbb632 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Registration.java @@ -0,0 +1,160 @@ +/* + * 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.dao.entities; + +import org.joda.time.DateTime; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author jean.deruelle@telestax.com + * @author maria.farooq@telestax.com + */ +@Immutable +public final class Registration implements Comparable { + private final Sid sid; + private final String instanceId; + private final DateTime dateCreated; + private final DateTime dateUpdated; + private final DateTime dateExpires; + private final String addressOfRecord; + private final String displayName; + private final String userName; + private final int timeToLive; + private final String location; + private final String userAgent; + private final boolean webrtc; + private final boolean isLBPresent; + private final Sid organizationSid; + + public Registration(final Sid sid, final String instanceId, final DateTime dateCreated, final DateTime dateUpdated, final String addressOfRecord, + final String displayName, final String userName, final String userAgent, final int timeToLive, + final String location, final boolean webRTC, final boolean isLBPresent, final Sid organizationSid) { + this(sid, instanceId, dateCreated, dateUpdated, DateTime.now().plusSeconds(timeToLive), addressOfRecord, displayName, userName, + userAgent, timeToLive, location, webRTC, isLBPresent, organizationSid); + } + + public Registration(final Sid sid, final String instanceId, final DateTime dateCreated, final DateTime dateUpdated, final DateTime dateExpires, + final String addressOfRecord, final String displayName, final String userName, final String userAgent, + final int timeToLive, final String location, final boolean webRTC, final boolean isLBPresent, final Sid organizationSid) { + super(); + this.sid = sid; + this.instanceId = instanceId; + this.dateCreated = dateCreated; + this.dateUpdated = dateUpdated; + this.dateExpires = dateExpires; + this.addressOfRecord = addressOfRecord; + this.displayName = displayName; + this.userName = userName; + this.location = location; + this.userAgent = userAgent; + this.timeToLive = timeToLive; + this.webrtc = webRTC; + this.isLBPresent = isLBPresent; //(isLBPresent != null) ? isLBPresent : false; + //https://github.com/RestComm/Restcomm-Connect/issues/2106 + this.organizationSid = organizationSid; + } + + public Sid getSid() { + return sid; + } + + public String getInstanceId() { return instanceId; } + + public DateTime getDateCreated() { + return dateCreated; + } + + public DateTime getDateUpdated() { + return dateUpdated; + } + + public DateTime getDateExpires() { + return dateExpires; + } + + public String getAddressOfRecord() { + return addressOfRecord; + } + + public String getDisplayName() { + return displayName; + } + + public String getUserName() { + return userName; + } + + public String getLocation() { + return location; + } + + public String getUserAgent() { + return userAgent; + } + + public int getTimeToLive() { + return timeToLive; + } + + public boolean isWebRTC() { + return webrtc; + } + + public boolean isLBPresent() { + return isLBPresent; + } + + public Sid getOrganizationSid() { + return organizationSid; + } + + public Registration setTimeToLive(final int timeToLive) { + final DateTime now = DateTime.now(); + return new Registration(sid, instanceId, dateCreated, now, now.plusSeconds(timeToLive), addressOfRecord, displayName, userName, + userAgent, timeToLive, location, webrtc, isLBPresent, organizationSid); + } + + public Registration updated() { + final DateTime now = DateTime.now(); + return new Registration(sid, instanceId, dateCreated, now, dateExpires, addressOfRecord, displayName, userName, userAgent, timeToLive, location, webrtc, isLBPresent, organizationSid); + } + + @Override + public int compareTo(Registration registration) { + // use reverse order of comparator to have registrations sorted in descending order + if (this.getDateUpdated().toDate().getTime() > registration.getDateUpdated().toDate().getTime()) + return -1; + else + return 1; + } + + @Override + public String toString() { + return "Registration [sid=" + sid + ", instanceId=" + instanceId + ", dateCreated=" + dateCreated + + ", dateUpdated=" + dateUpdated + ", dateExpires=" + dateExpires + ", addressOfRecord=" + + addressOfRecord + ", displayName=" + displayName + ", userName=" + userName + ", timeToLive=" + + timeToLive + ", location=" + location + ", userAgent=" + userAgent + ", webrtc=" + webrtc + + ", isLBPresent=" + isLBPresent + ", organizationSid=" + organizationSid + "]"; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RegistrationList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RegistrationList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RegistrationList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RegistrationList.java index 482d2228e9..f2c21d6d03 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RegistrationList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RegistrationList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RestCommResponse.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RestCommResponse.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RestCommResponse.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RestCommResponse.java index ac5890950b..285b7d87e3 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/RestCommResponse.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/RestCommResponse.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SearchFilterMode.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SearchFilterMode.java new file mode 100644 index 0000000000..ce6267933f --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SearchFilterMode.java @@ -0,0 +1,26 @@ +/* + * 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.dao.entities; + + +public enum SearchFilterMode { + PERFECT_MATCH, + WILDCARD_MATCH +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCode.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCode.java similarity index 96% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCode.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCode.java index 3164e9fa58..0036edb91a 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCode.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCode.java @@ -17,13 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.net.URI; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCodeList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCodeList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCodeList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCodeList.java index f4dc2596d7..d0db11150e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/ShortCodeList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/ShortCodeList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessage.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessage.java similarity index 88% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessage.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessage.java index 71f5206b26..6553804c79 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessage.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessage.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.math.BigDecimal; import java.net.URI; @@ -25,14 +25,16 @@ import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.stream.StreamEvent; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ @Immutable -public final class SmsMessage { +public final class SmsMessage implements StreamEvent { public static final int MAX_SIZE = 160; private final Sid sid; private final DateTime dateCreated; @@ -154,14 +156,21 @@ public static final class Builder { private Currency priceUnit; private String apiVersion; private URI uri; + private DateTime dateCreated; + private DateTime dateUpdated; private Builder() { super(); } public SmsMessage build() { - final DateTime now = DateTime.now(); - return new SmsMessage(sid, now, now, dateSent, accountSid, sender, recipient, body, status, direction, price, + if (dateCreated == null) { + dateCreated = DateTime.now(); + } + if (dateUpdated == null) { + dateUpdated = dateCreated; + } + return new SmsMessage(sid, dateCreated, dateUpdated, dateSent, accountSid, sender, recipient, body, status, direction, price, priceUnit, apiVersion, uri); } @@ -212,6 +221,14 @@ public void setApiVersion(final String apiVersion) { public void setUri(final URI uri) { this.uri = uri; } + + public void setDateCreated(DateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public void setDateUpdated(DateTime dateUpdated) { + this.dateUpdated = dateUpdated; + } } public enum Direction { diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageFilter.java new file mode 100644 index 0000000000..0df114c345 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageFilter.java @@ -0,0 +1,127 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author vunguyen + */ + +@Immutable +public class SmsMessageFilter { + + private final String accountSid; + private final List accountSidSet; // if not-null we need the cdrs that belong to several accounts + private final String recipient; + private final String sender; + private final Date startTime; // to initialize it pass string arguments with yyyy-MM-dd format + private final Date endTime; + private final String body; + private final Integer limit; + private final Integer offset; + private final String instanceid; + + public SmsMessageFilter(String accountSid, List accountSidSet, String recipient, String sender, String startTime, String endTime, + String body, Integer limit, Integer offset) throws ParseException { + this(accountSid, accountSidSet, recipient,sender,startTime,endTime, body, limit,offset,null); + } + + public SmsMessageFilter(String accountSid, List accountSidSet, String recipient, String sender, String startTime, String endTime, + String body, Integer limit, Integer offset, String instanceId) throws ParseException { + this.accountSid = accountSid; + this.accountSidSet = accountSidSet; + + // The LIKE keyword uses '%' to match any (including 0) number of characters, and '_' to match exactly one character + // Add here the '%' keyword so +15126002188 will be the same as 15126002188 and 6002188 + if (recipient != null) + recipient = "%".concat(recipient); + if (sender != null) + sender = "%".concat(sender); + + this.recipient = recipient; + this.sender = sender; + this.body = body; + this.limit = limit; + this.offset = offset; + if (startTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(startTime); + this.startTime = date; + } else + this.startTime = null; + + if (endTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(endTime); + this.endTime = date; + } else { + this.endTime = null; + } + if (instanceId != null && !instanceId.isEmpty()) { + this.instanceid = instanceId; + } else { + this.instanceid = null; + } + } + + public String getSid() { + return accountSid; + } + + public List getAccountSidSet() { + return accountSidSet; + } + + public String getRecipient() { + return recipient; + } + + public String getSender() { + return sender; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public String getBody() { + return body; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getInstanceid() { return instanceid; } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessageList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessageList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageList.java index 4fb8738c6a..2fe868c68f 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/SmsMessageList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/SmsMessageList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Transcription.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Transcription.java similarity index 96% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Transcription.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Transcription.java index 8c2e119d5c..39f83ce01d 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/Transcription.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Transcription.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.io.Serializable; import java.math.BigDecimal; @@ -26,8 +26,9 @@ import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionFilter.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionFilter.java new file mode 100644 index 0000000000..94ccae7741 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionFilter.java @@ -0,0 +1,107 @@ +/* + * 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.dao.entities; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author vunguyen + */ + +@Immutable +public class TranscriptionFilter { + private final String accountSid; + private final List accountSidSet; // if not-null we need the cdrs that belong to several accounts + private final Date startTime; // to initialize it pass string arguments with yyyy-MM-dd format + private final Date endTime; + private final String transcriptionText; + private final Integer limit; + private final Integer offset; + private final String instanceid; + + public TranscriptionFilter(String accountSid, List accountSidSet, String startTime, String endTime, + String transcriptionText, Integer limit, Integer offset) throws ParseException { + this(accountSid, accountSidSet, startTime,endTime, transcriptionText, limit,offset,null); + } + + public TranscriptionFilter(String accountSid, List accountSidSet, String startTime, String endTime, + String transcriptionText, Integer limit, Integer offset, String instanceId) throws ParseException { + this.accountSid = accountSid; + this.accountSidSet = accountSidSet; + + this.transcriptionText = transcriptionText; + this.limit = limit; + this.offset = offset; + if (startTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(startTime); + this.startTime = date; + } else + this.startTime = null; + + if (endTime != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd"); + Date date = parser.parse(endTime); + this.endTime = date; + } else { + this.endTime = null; + } + if (instanceId != null && !instanceId.isEmpty()) { + this.instanceid = instanceId; + } else { + this.instanceid = null; + } + } + + public String getSid() { + return accountSid; + } + + public List getAccountSidSet() { + return accountSidSet; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public String getTranscriptionText() { + return transcriptionText; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public String getInstanceid() { return instanceid; } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/TranscriptionList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionList.java similarity index 90% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/TranscriptionList.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionList.java index 11110b9914..6bf88566ab 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/TranscriptionList.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/TranscriptionList.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities; +package org.restcomm.connect.dao.entities; import java.util.List; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Usage.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Usage.java new file mode 100644 index 0000000000..3ca87d5718 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/Usage.java @@ -0,0 +1,151 @@ +/* + * 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.dao.entities; + +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.dao.Sid; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.net.URI; +import java.util.Currency; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@Immutable +public final class Usage implements Serializable { + private static final long serialVersionUID = 1L; + + private final Category category; + private final String description; + private final Sid accountSid; + private final DateTime startDate; + private final DateTime endDate; + private final Long usage; + private final String usageUnit; + private final Long count; + private final String countUnit; + private final BigDecimal price; + private final Currency priceUnit; + private final URI uri; + + public Usage(final Category category, final String description, final Sid accountSid, final DateTime startDate, final DateTime endDate, + final Long usage, final String usageUnit, final Long count, final String countUnit, final BigDecimal price, + final Currency priceUnit, final URI uri) { + super(); + this.category = category; + this.description = description; + this.accountSid = accountSid; + this.startDate = startDate; + this.endDate = endDate; + this.usage = usage; + this.usageUnit = usageUnit; + this.count = count; + this.countUnit = countUnit; + this.price = price; + this.priceUnit = priceUnit; + this.uri = uri; + } + + public Category getCategory() { + return category; + } + + public String getDescription() { + return description; + } + + public Sid getAccountSid() { + return accountSid; + } + + public DateTime getStartDate() { + return startDate; + } + + public DateTime getEndDate() { + return endDate; + } + + public Long getUsage() { + return usage; + } + + public String getUsageUnit() { + return usageUnit; + } + + public Long getCount() { + return count; + } + + public String getCountUnit() { + return countUnit; + } + + public BigDecimal getPrice() { + return price; + } + + public Currency getPriceUnit() { + return priceUnit; + } + + public URI getUri() { + return uri; + } + + public enum Category { + CALLS("calls"), CALLS_INBOUND("calls-inbound"), CALLS_INBOUND_LOCAL("calls-inbound-local"), + CALLS_INBOUND_TOLLFREE("calls-inbound-tollfree"), CALLS_OUTBOUND("calls-outbound"), + CALLS_CLIENT("calls-client"), CALLS_SIP("calls-sip"), SMS("sms"), SMS_INBOUND("sms-inbound"), + SMS_INBOUND_SHORTCODE("sms-inbound-shortcode"), SMS_INBOUND_LONGCODE("sms-inbound-longcode"), + SMS_OUTBOUND("sms-outbound"), SMS_OUTBOUND_SHORTCODE("sms-outbound-shortcode"), + SMS_OUTBOUND_LONGCODE("sms-outbound-longcode"), PHONENUMBERS("phonenumbers"), + PHONENUMBERS_TOLLFREE("phonenumbers-tollfree"), PHONENUMBERS_LOCAL("phonenumbers-local"), + SHORTCODES("shortcodes"), SHORTCODES_VANITY("shortcodes-vanity"), + SHORTCODES_RANDOM("shortcodes-random"), SHORTCODES_CUSTOMEROWNED("shortcodes-customerowned"), + CALLERIDLOOKUPS("calleridlookups"), RECORDINGS("recordings"), TRANSCRIPTIONS("transcriptions"), + RECORDINGSTORAGE("recordingstorage"), TOTALPRICE("totalprice"); + + private final String text; + + private Category(final String text) { + this.text = text; + } + + public static Category getCategoryValue(final String text) { + final Category[] values = values(); + for (final Category value : values) { + if (value.toString().equals(text)) { + return value; + } + } + throw new IllegalArgumentException(text + " is not a valid category."); + } + + @Override + public String toString() { + return text; + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/UsageList.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/UsageList.java new file mode 100644 index 0000000000..7e12523104 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/UsageList.java @@ -0,0 +1,41 @@ +/* + * 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.dao.entities; + +import java.util.List; + +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@NotThreadSafe +public final class UsageList { + private final List usages; + + public UsageList(final List usages) { + super(); + this.usages = usages; + } + + public List getUsages() { + return usages; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/CredentialsMatcher.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/CredentialsMatcher.java similarity index 93% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/CredentialsMatcher.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/CredentialsMatcher.java index baf898055a..78c898ea39 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/CredentialsMatcher.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/CredentialsMatcher.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities.shiro; +package org.restcomm.connect.dao.entities.shiro; import org.apache.commons.codec.digest.DigestUtils; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/Realm.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/Realm.java similarity index 87% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/Realm.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/Realm.java index 8747c9cc24..d6ba3d810e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/Realm.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/Realm.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities.shiro; +package org.restcomm.connect.dao.entities.shiro; import java.util.HashMap; import java.util.HashSet; @@ -35,15 +35,15 @@ import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.authz.SimpleRole; -import org.apache.shiro.authz.permission.DomainPermission; +import org.apache.shiro.authz.permission.WildcardPermission; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -91,7 +91,7 @@ protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken t sid = new Sid(username); account = accounts.getAccount(sid); } else { - account = accounts.getAccount(username); + account = accounts.getAccountToAuthenticate(username); sid = account.getSid(); } @@ -139,9 +139,10 @@ private void loadSecurityRoles(final Configuration configuration) { if (numberOfPermissions > 0) { final SimpleRole role = new SimpleRole(name); for (int permissionIndex = 0; permissionIndex < numberOfPermissions; permissionIndex++) { - buffer = new StringBuilder(); - buffer.append(prefix).append(".permission(").append(permissionIndex).append(")"); - final Permission permission = new DomainPermission(buffer.toString()); + String permissionName = permissions.get(permissionIndex); + //buffer = new StringBuilder(); + //buffer.append(prefix).append(".permission(").append(permissionIndex).append(")"); + final Permission permission = new WildcardPermission(permissionName); role.add(permission); } roles.put(name, role); diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/ShiroResources.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/ShiroResources.java similarity index 93% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/ShiroResources.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/ShiroResources.java index 37d3dc6199..b24ba3bea3 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/entities/shiro/ShiroResources.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/entities/shiro/ShiroResources.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.entities.shiro; +package org.restcomm.connect.dao.entities.shiro; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/exceptions/AccountHierarchyDepthCrossed.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/exceptions/AccountHierarchyDepthCrossed.java new file mode 100644 index 0000000000..c748d9010a --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/exceptions/AccountHierarchyDepthCrossed.java @@ -0,0 +1,51 @@ +/* + * 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.dao.exceptions; + +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + +/** + * Thrown when an operation needs to process account hierarchies with greater + * depth then the one allowed. + * + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public class AccountHierarchyDepthCrossed extends RestcommRuntimeException { + + public AccountHierarchyDepthCrossed() { + } + + public AccountHierarchyDepthCrossed(String message) { + super(message); + } + + public AccountHierarchyDepthCrossed(String message, Throwable cause) { + super(message, cause); + } + + public AccountHierarchyDepthCrossed(Throwable cause) { + super(cause); + } + + public AccountHierarchyDepthCrossed(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAccountsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAccountsDao.java new file mode 100644 index 0000000000..bcf91cc44f --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAccountsDao.java @@ -0,0 +1,290 @@ +/* + * 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.dao.mybatis; + +import static org.restcomm.connect.dao.DaoUtils.readAccountStatus; +import static org.restcomm.connect.dao.DaoUtils.readAccountType; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeAccountStatus; +import static org.restcomm.connect.dao.DaoUtils.writeAccountType; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisAccountsDao implements AccountsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.AccountsDao."; + private Integer accountRecursionDepth = 3; // maximum value for recursive account queries + private final SqlSessionFactory sessions; + + public MybatisAccountsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + public void setAccountRecursionDepth(Integer accountRecursionDepth) { + this.accountRecursionDepth = accountRecursionDepth; + } + + @Override + public void addAccount(final Account account) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addAccount", toMap(account)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Account getAccount(final Sid sid) { + return getAccount(namespace + "getAccount", sid.toString()); + } + + @Override + public Account getAccount(final String name) { + Account account = null; + + account = getAccount(namespace + "getAccountByFriendlyName", name); + if (account == null) { + account = getAccount(namespace + "getAccountByEmail", name); + } + if (account == null) { + account = getAccount(namespace + "getAccount", name); + } + + return account; + } + + @Override + public Account getAccountToAuthenticate(final String name) { + Account account = null; + + account = getAccount(namespace + "getAccountByEmail", name); + if (account == null) { + account = getAccount(namespace + "getAccount", name); + } + + return account; + } + + private Account getAccount(final String selector, final Object parameters) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(selector, parameters); + if (result != null) { + return toAccount(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getChildAccounts(final Sid parentSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getChildAccounts", parentSid.toString()); + final List accounts = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + accounts.add(toAccount(result)); + } + } + return accounts; + } finally { + session.close(); + } + } + + @Override + public void removeAccount(final Sid sid) { + removeAccount(namespace + "removeAccount", sid); + } + + private void removeAccount(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateAccount(final Account account) { + updateAccount(namespace + "updateAccount", account); + } + + @Override + public List getSubAccountSidsRecursive(Sid parentAccountSid) { + List parentList = new ArrayList(); + parentList.add(parentAccountSid.toString()); + List allChildren = new ArrayList(); + + int depth = 1; + List childrenList = getSubAccountsSids(parentList); + while (childrenList != null && !childrenList.isEmpty() && depth <= accountRecursionDepth) { + allChildren.addAll(childrenList); + childrenList = getSubAccountsSids(childrenList); // retrieve children's children + + depth ++; + } + + return allChildren; + } + + @Override + public List getAccountLineage(Sid accountSid) throws AccountHierarchyDepthCrossed { + if (accountSid == null) + return null; + List ancestorList = new ArrayList(); + Sid sid = accountSid; + Account account = getAccount(sid); + if (account == null) + throw new IllegalArgumentException("Wrong accountSid is given to search for ancestor on it. This account does not even exist"); + int depth = 1; // already having one-level of accounts + while ( true ) { + Sid parentSid = account.getParentSid(); + if (parentSid != null) { + depth ++; + if (depth > accountRecursionDepth) + throw new AccountHierarchyDepthCrossed(); + ancestorList.add(parentSid.toString()); + Account parentAccount = getAccount(parentSid); + if (parentAccount == null) + throw new IllegalStateException("Parent account " + parentSid.toString() + " does not exist although its child does " + account.getSid().toString()); + account = parentAccount; + } else + break; + } + return ancestorList; + } + + @Override + public List getAccountLineage(Account account) throws AccountHierarchyDepthCrossed { + if (account == null) + return null; + List lineage = new ArrayList(); + Sid parentSid = account.getParentSid(); + if (parentSid != null) { + lineage.add(parentSid.toString()); + lineage.addAll(getAccountLineage(parentSid)); + } + return lineage; + } + + private List getSubAccountsSids(List parentAccountSidList) { + final SqlSession session = sessions.openSession(); + try { + final List results = session.selectList(namespace + "getSubAccountSids", parentAccountSidList); + return results; + } finally { + session.close(); + } + } + + private void updateAccount(final String selector, final Account account) { + final SqlSession session = sessions.openSession(); + try { + session.update(selector, toMap(account)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public List getAccountsByOrganization(final Sid organizationSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getAccountsByOrganization", organizationSid.toString()); + final List accounts = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + accounts.add(toAccount(result)); + } + } + return accounts; + } finally { + session.close(); + } + } + + private Account toAccount(final Map map) { + final Sid sid = readSid(map.get("sid")); + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + final String emailAddress = readString(map.get("email_address")); + final String friendlyName = readString(map.get("friendly_name")); + final Sid parentSid = readSid(map.get("parent_sid")); + final Account.Type type = readAccountType(map.get("type")); + final Account.Status status = readAccountStatus(map.get("status")); + final String authToken = readString(map.get("auth_token")); + final String role = readString(map.get("role")); + final URI uri = readUri(map.get("uri")); + final Sid organizationSid = readSid(map.get("organization_sid")); + return new Account(sid, dateCreated, dateUpdated, emailAddress, friendlyName, parentSid, type, status, authToken, + role, uri, organizationSid); + } + + private Map toMap(final Account account) { + final Map map = new HashMap(); + map.put("sid", writeSid(account.getSid())); + map.put("date_created", writeDateTime(account.getDateCreated())); + map.put("date_updated", writeDateTime(account.getDateUpdated())); + map.put("email_address", account.getEmailAddress()); + map.put("friendly_name", account.getFriendlyName()); + map.put("parent_sid", writeSid(account.getParentSid())); + map.put("type", writeAccountType(account.getType())); + map.put("status", writeAccountStatus(account.getStatus())); + map.put("auth_token", account.getAuthToken()); + map.put("role", account.getRole()); + map.put("uri", writeUri(account.getUri())); + map.put("organization_sid", writeSid(account.getOrganizationSid())); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAnnouncementsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAnnouncementsDao.java similarity index 76% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAnnouncementsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAnnouncementsDao.java index b45191e1e6..3b043e12dd 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAnnouncementsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAnnouncementsDao.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.net.URI; import java.util.ArrayList; @@ -11,10 +11,10 @@ import org.joda.time.DateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.AnnouncementsDao; -import org.mobicents.servlet.restcomm.entities.Announcement; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.AnnouncementsDao; +import org.restcomm.connect.dao.entities.Announcement; +import org.restcomm.connect.commons.dao.Sid; /** * @author George Vagenas @@ -95,24 +95,24 @@ private void deleteAnnouncement(final String selector, final Sid sid) { private Map toMap(final Announcement announcement) { final Map map = new HashMap(); - map.put("sid", writeSid(announcement.getSid())); - map.put("date_created", writeDateTime(announcement.getDateCreated())); - map.put("account_sid", writeSid(announcement.getAccountSid())); + map.put("sid", DaoUtils.writeSid(announcement.getSid())); + map.put("date_created", DaoUtils.writeDateTime(announcement.getDateCreated())); + map.put("account_sid", DaoUtils.writeSid(announcement.getAccountSid())); map.put("gender", announcement.getGender()); map.put("language", announcement.getLanguage()); map.put("text", announcement.getText()); - map.put("uri", writeUri(announcement.getUri())); + map.put("uri", DaoUtils.writeUri(announcement.getUri())); return map; } private Announcement toAnnouncement(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final Sid accountSid = readSid(map.get("account_sid")); - final String gender = readString(map.get("gender")); - final String language = readString(map.get("language")); - final String text = readString(map.get("text")); - final URI uri = readUri(map.get("uri")); + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String gender = DaoUtils.readString(map.get("gender")); + final String language = DaoUtils.readString(map.get("language")); + final String text = DaoUtils.readString(map.get("text")); + final URI uri = DaoUtils.readUri(map.get("uri")); return new Announcement(sid, dateCreated, accountSid, gender, language, text, uri); } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisApplicationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisApplicationsDao.java new file mode 100644 index 0000000000..557288b65e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisApplicationsDao.java @@ -0,0 +1,233 @@ +/* + * 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.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.ApplicationNumberSummary; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.restcomm.connect.dao.DaoUtils.readApplicationKind; +import static org.restcomm.connect.dao.DaoUtils.readBoolean; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeApplicationKind; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class MybatisApplicationsDao implements ApplicationsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ApplicationsDao."; + private final SqlSessionFactory sessions; + + public MybatisApplicationsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addApplication(final Application application) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addApplication", toMap(application)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Application getApplication(final Sid sid) { + Application application = getApplication(namespace + "getApplication", sid.toString()); + return application; + } + + @Override + public Application getApplication(final String friendlyName) { + return getApplication(namespace + "getApplicationByFriendlyName", friendlyName); + } + + private Application getApplication(final String selector, final String parameter) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(selector, parameter); + if (result != null) { + return toApplication(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getApplicationsWithNumbers(Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getApplicationsAndNumbers", accountSid.toString()); + final List applications = new ArrayList(); + if (results != null && !results.isEmpty()) { + Application previousApp = null; + Application app = null; + for (final Map result : results) { + app = toApplication(result); + if (previousApp != null && previousApp.getSid().equals(app.getSid()) ) + app = previousApp; + // if there is a number bound to this application populate the latter with the number details + if (result.get("num_sid") != null) { + populateApplicationWithNumber(app, result, "num_"); + } + if (previousApp == null || !previousApp.getSid().equals(app.getSid())) { + // is this is a new application in the result map add it to the list. Remember, the same app can be returned many times if it's related to many numbers + applications.add(app); + } + previousApp = app; + } + } + return applications; + } finally { + session.close(); + } + } + + @Override + public List getApplications(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getApplications", accountSid.toString()); + final List applications = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + applications.add(toApplication(result)); + } + } + return applications; + } finally { + session.close(); + } + } + + @Override + public void removeApplication(final Sid sid) { + removeApplications("removeApplication", sid); + } + + @Override + public void removeApplications(final Sid accountSid) { + removeApplications("removeApplications", accountSid); + } + + private void removeApplications(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateApplication(final Application application) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateApplication", toMap(application)); + session.commit(); + } finally { + session.close(); + } + } + + private Application toApplication(final Map map) { + final Sid sid = readSid(map.get("sid")); + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + final String friendlyName = readString(map.get("friendly_name")); + final Sid accountSid = readSid(map.get("account_sid")); + final String apiVersion = readString(map.get("api_version")); + final Boolean hasVoiceCallerIdLookup = readBoolean(map.get("voice_caller_id_lookup")); + final URI uri = readUri(map.get("uri")); + final URI rcmlUrl = readUri(map.get("rcml_url")); + final Application.Kind kind = readApplicationKind(map.get("kind")); + return new Application(sid, dateCreated, dateUpdated, friendlyName, accountSid, apiVersion, hasVoiceCallerIdLookup, + uri, rcmlUrl, kind); + } + + /** + * Populates application.numbers field with information of one or more numbers. The 'numbers' list is created if + * already null and an IncomingPhoneNumber is added into it based on information from the map. Invoking the same method + * several times to add more numbers to the same list is possible. + * + * @param application + * @param map + * @param field_prefix + * @return + */ + private void populateApplicationWithNumber(Application application, final Map map, String field_prefix) { + // first create the number + ApplicationNumberSummary number = new ApplicationNumberSummary( + readString(map.get(field_prefix + "sid")), + readString(map.get(field_prefix + "friendly_name")), + readString(map.get(field_prefix + "phone_number")), + readString(map.get(field_prefix + "voice_application_sid")), + readString(map.get(field_prefix + "sms_application_sid")), + readString(map.get(field_prefix + "ussd_application_sid")), + readString(map.get(field_prefix + "refer_application_sid")) + ); + List numbers = application.getNumbers(); + if (numbers == null) { + numbers = new ArrayList(); + application.setNumbers(numbers); + } + numbers.add(number); + } + + private Map toMap(final Application application) { + final Map map = new HashMap(); + map.put("sid", writeSid(application.getSid())); + map.put("date_created", writeDateTime(application.getDateCreated())); + map.put("date_updated", writeDateTime(application.getDateUpdated())); + map.put("friendly_name", application.getFriendlyName()); + map.put("account_sid", writeSid(application.getAccountSid())); + map.put("api_version", application.getApiVersion()); + map.put("voice_caller_id_lookup", application.hasVoiceCallerIdLookup()); + map.put("uri", writeUri(application.getUri())); + map.put("rcml_url", writeUri(application.getRcmlUrl())); + map.put("kind", writeApplicationKind(application.getKind())); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAvailablePhoneNumbersDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAvailablePhoneNumbersDao.java similarity index 81% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAvailablePhoneNumbersDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAvailablePhoneNumbersDao.java index 27f5cf889a..738912422c 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisAvailablePhoneNumbersDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisAvailablePhoneNumbersDao.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.util.ArrayList; import java.util.HashMap; @@ -26,12 +26,11 @@ import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; -import org.mobicents.servlet.restcomm.dao.AvailablePhoneNumbersDao; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.AvailablePhoneNumbersDao; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; - -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumber; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.AvailablePhoneNumber; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -140,21 +139,22 @@ public void removeAvailablePhoneNumber(final String phoneNumber) { } private AvailablePhoneNumber toAvailablePhoneNumber(final Map map) { - final String friendlyName = readString(map.get("friendly_name")); - final String phoneNumber = readString(map.get("phone_number")); - final Integer lata = readInteger(map.get("lata")); - final String rateCenter = readString(map.get("rate_center")); - final Double latitude = readDouble(map.get("latitude")); - final Double longitude = readDouble(map.get("longitude")); - final String region = readString(map.get("region")); - final Integer postalCode = readInteger(map.get("postal_code")); - final String isoCountry = readString(map.get("iso_country")); - final Boolean voiceCapable = readBoolean(map.get("voice_capable")); - final Boolean smsCapable = readBoolean(map.get("sms_capable")); - final Boolean mmsCapable = readBoolean(map.get("mms_capable")); - final Boolean faxCapable = readBoolean(map.get("fax_capable")); + final String friendlyName = DaoUtils.readString(map.get("friendly_name")); + final String phoneNumber = DaoUtils.readString(map.get("phone_number")); + final Integer lata = DaoUtils.readInteger(map.get("lata")); + final String rateCenter = DaoUtils.readString(map.get("rate_center")); + final Double latitude = DaoUtils.readDouble(map.get("latitude")); + final Double longitude = DaoUtils.readDouble(map.get("longitude")); + final String region = DaoUtils.readString(map.get("region")); + final Integer postalCode = DaoUtils.readInteger(map.get("postal_code")); + final String isoCountry = DaoUtils.readString(map.get("iso_country")); + final Boolean voiceCapable = DaoUtils.readBoolean(map.get("voice_capable")); + final Boolean smsCapable = DaoUtils.readBoolean(map.get("sms_capable")); + final Boolean mmsCapable = DaoUtils.readBoolean(map.get("mms_capable")); + final Boolean faxCapable = DaoUtils.readBoolean(map.get("fax_capable")); + final String cost = DaoUtils.readString(map.get("cost")); return new AvailablePhoneNumber(friendlyName, phoneNumber, lata, rateCenter, latitude, longitude, region, postalCode, - isoCountry, voiceCapable, smsCapable, mmsCapable, faxCapable); + isoCountry, cost, voiceCapable, smsCapable, mmsCapable, faxCapable); } private Map toMap(final AvailablePhoneNumber availablePhoneNumber) { @@ -172,6 +172,7 @@ private Map toMap(final AvailablePhoneNumber availablePhoneNumbe map.put("sms_capable", availablePhoneNumber.isSmsCapable()); map.put("mms_capable", availablePhoneNumber.isMmsCapable()); map.put("fax_capable", availablePhoneNumber.isFaxCapable()); + map.put("cost", availablePhoneNumber.getCost()); return map; } } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisCallDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisCallDetailRecordsDao.java new file mode 100644 index 0000000000..45e5085ce8 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisCallDetailRecordsDao.java @@ -0,0 +1,384 @@ +/* + * 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.dao.mybatis; + +import java.math.BigDecimal; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Currency; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class MybatisCallDetailRecordsDao implements CallDetailRecordsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.CallDetailRecordsDao."; + private final SqlSessionFactory sessions; + + public MybatisCallDetailRecordsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addCallDetailRecord(final CallDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addCallDetailRecord", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public CallDetailRecord getCallDetailRecord(final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getCallDetailRecord", sid.toString()); + if (result != null) { + return toCallDetailRecord(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + // Issue 110 + @Override + public Integer getTotalCallDetailRecords(CallDetailRecordFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalCallDetailRecordByUsingFilters", filter); + return total; + } finally { + session.close(); + } + } + + @Override + public Integer getInProgressCallsByClientName(String client) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getInProgressCallsByClientName", client); + return total; + } finally { + session.close(); + } + } + + @Override + public Integer getInProgressCallsByAccountSid(String accountSid) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getInProgressCallsByAccountSid", accountSid); + return total; + } finally { + session.close(); + } + } + + @Override + public Integer getTotalRunningCallDetailRecordsByConferenceSid(Sid conferenceSid){ + + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalRunningCallDetailRecordsByConferenceSid", conferenceSid.toString()); + return total; + } finally { + session.close(); + } + + } + // Issue 153: https://bitbucket.org/telestax/telscale-restcomm/issue/153 + // Issue 110: https://bitbucket.org/telestax/telscale-restcomm/issue/110 + @Override + public List getCallDetailRecords(CallDetailRecordFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getCallDetailRecordByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toCallDetailRecord(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public List getCallDetailRecordsByAccountSid(final Sid accountSid) { + return getCallDetailRecords(namespace + "getCallDetailRecords", accountSid.toString()); + } + + @Override + public List getCallDetailRecordsByRecipient(final String recipient) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByRecipient", recipient); + } + + @Override + public List getCallDetailRecordsBySender(final String sender) { + return getCallDetailRecords(namespace + "getCallDetailRecordsBySender", sender); + } + + @Override + public List getCallDetailRecordsByStatus(final String status) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByStatus", status); + } + + @Override + public List getCallDetailRecordsByStartTime(final DateTime startTime) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByStartTime", startTime.toDate()); + } + + @Override + public List getCallDetailRecordsByEndTime(final DateTime endTime) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByEndTime", endTime.toDate()); + } + + @Override + public List getCallDetailRecordsByStarTimeAndEndTime(final DateTime endTime) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByStarTimeAndEndTime", endTime.toDate()); + } + + @Override + public List getCallDetailRecordsByParentCall(final Sid parentCallSid) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByParentCall", parentCallSid.toString()); + } + + @Override + public List getCallDetailRecordsByConferenceSid(final Sid conferenceSid) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByConferenceSid", conferenceSid.toString()); + } + + @Override + public List getRunningCallDetailRecordsByConferenceSid(final Sid conferenceSid) { + return getCallDetailRecords(namespace + "getRunningCallDetailRecordsByConferenceSid", conferenceSid.toString()); + } + + @Override + public List getCallDetailRecordsByInstanceId(final Sid instanceId) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByInstanceId", instanceId.toString()); + } + + @Override + public List getInCompleteCallDetailRecordsByInstanceId(Sid instanceId) { + return getCallDetailRecords(namespace + "getInCompleteCallDetailRecordsByInstanceId", instanceId.toString()); + } + + @Override + public List getCallDetailRecordsByMsId(String msId) { + return getCallDetailRecords(namespace + "getCallDetailRecordsByMsId", msId); + } + + @Override + public Double getAverageCallDurationLast24Hours(Sid instanceId) throws ParseException { + DateTime now = DateTime.now(); + DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd"); + SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd"); + + Date today = formatter.parse(now.toString(fmt)); + + Map params = new HashMap(); + params.put("instanceid", instanceId.toString()); + params.put("startTime", today); + + final SqlSession session = sessions.openSession(); + try { + final Double total = session.selectOne(namespace + "getAverageCallDurationLast24Hours", params); + return total; + } finally { + session.close(); + } + } + + @Override + public Double getAverageCallDurationLastHour(Sid instanceId) throws ParseException { + SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:00:00"); + String hour = formatter.format(Calendar.getInstance().getTime()); + Date lastHour = formatter.parse(hour); + + Map params = new HashMap(); + params.put("instanceid", instanceId.toString()); + params.put("startTime", lastHour); + + final SqlSession session = sessions.openSession(); + try { + final Double total = session.selectOne(namespace + "getAverageCallDurationLastHour", params); + return total; + } finally { + session.close(); + } + } + + private List getCallDetailRecords(final String selector, Object input) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(selector, input); + final List cdrs = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toCallDetailRecord(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public void removeCallDetailRecord(final Sid sid) { + removeCallDetailRecords(namespace + "removeCallDetailRecord", sid); + } + + @Override + public void removeCallDetailRecords(final Sid accountSid) { + removeCallDetailRecords(namespace + "removeCallDetailRecords", accountSid); + } + + private void removeCallDetailRecords(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateCallDetailRecord(final CallDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateCallDetailRecord", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateInCompleteCallDetailRecordsToCompletedByInstanceId(Sid instanceId) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateInCompleteCallDetailRecordsToCompletedByInstanceId", instanceId.toString()); + session.commit(); + } finally { + session.close(); + } + } + + private CallDetailRecord toCallDetailRecord(final Map map) { + final String msId = DaoUtils.readString(map.get("ms_id")); + final Sid sid = DaoUtils.readSid(map.get("sid")); + final String instanceId = DaoUtils.readString(map.get("instanceid")); + final Sid parentCallSid = DaoUtils.readSid(map.get("parent_call_sid")); + final Sid conferenceSid = DaoUtils.readSid(map.get("conference_sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String to = DaoUtils.readString(map.get("recipient")); + final String from = DaoUtils.readString(map.get("sender")); + final Sid phoneNumberSid = DaoUtils.readSid(map.get("phone_number_sid")); + final String status = DaoUtils.readString(map.get("status")); + final DateTime startTime = DaoUtils.readDateTime(map.get("start_time")); + final DateTime endTime = DaoUtils.readDateTime(map.get("end_time")); + final Integer duration = DaoUtils.readInteger(map.get("duration")); + final Integer ringDuration = DaoUtils.readInteger(map.get("ring_duration")); + final BigDecimal price = DaoUtils.readBigDecimal(map.get("price")); + final Currency priceUnit = DaoUtils.readCurrency(map.get("price_unit")); + final String direction = DaoUtils.readString(map.get("direction")); + final String answeredBy = DaoUtils.readString(map.get("answered_by")); + final String apiVersion = DaoUtils.readString(map.get("api_version")); + final String forwardedFrom = DaoUtils.readString(map.get("forwarded_from")); + final String callerName = DaoUtils.readString(map.get("caller_name")); + final URI uri = DaoUtils.readUri(map.get("uri")); + final String callPath = DaoUtils.readString(map.get("call_path")); + final Boolean muted = DaoUtils.readBoolean(map.get("muted")); + final Boolean startConferenceOnEnter = DaoUtils.readBoolean(map.get("start_conference_on_enter")); + final Boolean endConferenceOnExit = DaoUtils.readBoolean(map.get("end_conference_on_exit")); + final Boolean onHold = DaoUtils.readBoolean(map.get("on_hold")); + return new CallDetailRecord(sid, instanceId, parentCallSid, conferenceSid, dateCreated, dateUpdated, accountSid, to, from, phoneNumberSid, status, + startTime, endTime, duration, price, priceUnit, direction, answeredBy, apiVersion, forwardedFrom, callerName, + uri, callPath, ringDuration, muted, startConferenceOnEnter, endConferenceOnExit, onHold, msId); + } + + private Map toMap(final CallDetailRecord cdr) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(cdr.getSid())); + map.put("instanceid", cdr.getInstanceId()); + map.put("parent_call_sid", DaoUtils.writeSid(cdr.getParentCallSid())); + map.put("conference_sid", DaoUtils.writeSid(cdr.getConferenceSid())); + map.put("date_created", DaoUtils.writeDateTime(cdr.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(cdr.getDateUpdated())); + map.put("account_sid", DaoUtils.writeSid(cdr.getAccountSid())); + map.put("to", cdr.getTo()); + map.put("from", cdr.getFrom()); + map.put("phone_number_sid", DaoUtils.writeSid(cdr.getPhoneNumberSid())); + map.put("status", cdr.getStatus()); + map.put("start_time", DaoUtils.writeDateTime(cdr.getStartTime())); + map.put("end_time", DaoUtils.writeDateTime(cdr.getEndTime())); + map.put("duration", cdr.getDuration()); + map.put("ring_duration", cdr.getRingDuration()); + map.put("price", DaoUtils.writeBigDecimal(cdr.getPrice())); + map.put("direction", cdr.getDirection()); + map.put("answered_by", cdr.getAnsweredBy()); + map.put("api_version", cdr.getApiVersion()); + map.put("forwarded_from", cdr.getForwardedFrom()); + map.put("caller_name", cdr.getCallerName()); + map.put("uri", DaoUtils.writeUri(cdr.getUri())); + map.put("call_path", cdr.getCallPath()); + map.put("muted", cdr.isMuted()); + map.put("start_conference_on_enter", cdr.isStartConferenceOnEnter()); + map.put("end_conference_on_exit", cdr.isEndConferenceOnExit()); + map.put("on_hold", cdr.isOnHold()); + map.put("ms_id", cdr.getMsId()); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisClientsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisClientsDao.java similarity index 75% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisClientsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisClientsDao.java index 08f73165ef..5ba8b8d24e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisClientsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisClientsDao.java @@ -17,7 +17,16 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; + +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readInteger; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; import java.net.URI; import java.util.ArrayList; @@ -27,17 +36,15 @@ import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; - import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.ClientsDao; -import org.mobicents.servlet.restcomm.entities.Client; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.entities.Client; /** * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) */ @NotThreadSafe public final class MybatisClientsDao implements ClientsDao { @@ -66,11 +73,14 @@ public Client getClient(final Sid sid) { } @Override - public Client getClient(final String login) { - return getClient(namespace + "getClientByLogin", login); + public Client getClient(final String login, Sid organizationSid) { + final Map map = new HashMap(); + map.put("login", login); + map.put("organization_sid", writeSid(organizationSid)); + return getClient(namespace + "getClientByLogin", map); } - private Client getClient(final String selector, final String parameter) { + private Client getClient(final String selector, final Object parameter) { final SqlSession session = sessions.openSession(); try { final Map result = session.selectOne(selector, parameter); @@ -101,6 +111,23 @@ public List getClients(final Sid accountSid) { } } + @Override + public List getAllClients() { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getAllClients"); + final List clients = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + clients.add(toClient(result)); + } + } + return clients; + } finally { + session.close(); + } + } + @Override public void removeClient(final Sid sid) { removeClients(namespace + "removeClient", sid); @@ -148,10 +175,13 @@ private Client toClient(final Map map) { final String voiceFallbackMethod = readString(map.get("voice_fallback_method")); final Sid voiceApplicationSid = readSid(map.get("voice_application_sid")); final URI uri = readUri(map.get("uri")); + final String pushClientIdentity = readString(map.get("push_client_identity")); return new Client(sid, dateCreated, dateUpdated, accountSid, apiVersion, friendlyName, login, password, status, - voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri); + voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, voiceApplicationSid, uri, pushClientIdentity); } + + private Map toMap(final Client client) { final Map map = new HashMap(); map.put("sid", writeSid(client.getSid())); @@ -169,6 +199,7 @@ private Map toMap(final Client client) { map.put("voice_fallback_method", client.getVoiceFallbackMethod()); map.put("voice_application_sid", writeSid(client.getVoiceApplicationSid())); map.put("uri", writeUri(client.getUri())); + map.put("push_client_identity", client.getPushClientIdentity()); return map; } } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisConferenceDetailRecordsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisConferenceDetailRecordsDao.java new file mode 100644 index 0000000000..5777dbf463 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisConferenceDetailRecordsDao.java @@ -0,0 +1,291 @@ +/* + * 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.dao.mybatis; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.ConferenceDetailRecordsDao; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.dao.entities.ConferenceDetailRecordFilter; +import org.restcomm.connect.dao.entities.ConferenceRecordCountFilter; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisConferenceDetailRecordsDao implements ConferenceDetailRecordsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ConferenceDetailRecordsDao."; + private final SqlSessionFactory sessions; + + public MybatisConferenceDetailRecordsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public int addConferenceDetailRecord(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + int effectedRows = 0; + try { + effectedRows = session.insert(namespace + "addConferenceDetailRecord", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + return effectedRows; + } + + @Override + public ConferenceDetailRecord getConferenceDetailRecord(Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getConferenceDetailRecord", sid.toString()); + if (result != null) { + return toConferenceDetailRecord(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public Integer getTotalConferenceDetailRecords(ConferenceDetailRecordFilter filter) { + + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalConferenceDetailRecordByUsingFilters", filter); + return total; + } finally { + session.close(); + } + + } + + + @Override + public Integer countByFilter(ConferenceRecordCountFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "countByFilter", filter); + return total; + } finally { + session.close(); + } + } + + @Override + public List getConferenceDetailRecords(ConferenceDetailRecordFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getConferenceDetailRecordByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toConferenceDetailRecord(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public List getConferenceDetailRecords(final Sid accountSid) { + return getConferenceDetailRecords(namespace + "getConferenceDetailRecords", accountSid.toString()); + } + + @Override + public List getConferenceDetailRecordsByStatus(String status) { + return getConferenceDetailRecords(namespace + "getConferenceDetailRecordsByStatus", status); + } + + @Override + public List getConferenceDetailRecordsByDateCreated(final DateTime dateCreated) { + return getConferenceDetailRecords(namespace + "getConferenceDetailRecordsByDateCreated", dateCreated.toDate()); + } + + @Override + public List getConferenceDetailRecordsByDateUpdated(final DateTime dateUpdated) { + return getConferenceDetailRecords(namespace + "getConferenceDetailRecordsByDateUpdated", dateUpdated.toDate()); + } + + @Override + public void updateConferenceDetailRecordStatus(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateConferenceDetailRecordStatus", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateConferenceDetailRecordMasterEndpointID(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateConferenceDetailRecordMasterEndpointID", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateConferenceDetailRecordMasterBridgeEndpointID(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateConferenceDetailRecordMasterBridgeEndpointID", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateMasterPresent(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateMasterPresent", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateModeratorPresent(ConferenceDetailRecord cdr) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateModeratorPresent", toMap(cdr)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public boolean completeConferenceDetailRecord(Map params) { + final SqlSession session = sessions.openSession(); + try { + session.selectOne(namespace + "completeConferenceDetailRecord", params); + return (boolean)params.get("completed"); + } finally { + session.close(); + } + } + + @Override + public void removeConferenceDetailRecord(Sid sid) { + // TODO Add support for conference modification after basic API's as twillio's + } + + @Override + public void removeConferenceDetailRecords(Sid accountSid) { + // TODO Add support for conference modification after basic API's as twillio's + } + + private List getConferenceDetailRecords(final String selector, Object input) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(selector, input); + final List cdrs = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toConferenceDetailRecord(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + private ConferenceDetailRecord toConferenceDetailRecord(final Map map) { + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String status = DaoUtils.readString(map.get("status")); + final String friendlyName = DaoUtils.readString(map.get("friendly_name")); + final String apiVersion = DaoUtils.readString(map.get("api_version")); + final URI uri = DaoUtils.readUri(map.get("uri")); + final String msId = DaoUtils.readString(map.get("master_ms_id")); + final String masterConferenceEndpointId = DaoUtils.readString(map.get("master_conference_endpoint_id")); + final String masterIVREndpointId = DaoUtils.readString(map.get("master_ivr_endpoint_id")); + boolean masterPresent = false; + String masterIVREndpointSessionId = null; + String masterBridgeEndpointId = null; + String masterBridgeEndpointSessionId = null; + String masterBridgeConnectionIdentifier = null; + String masterIVRConnectionIdentifier = null; + boolean moderatorPresent = false; + try { + masterPresent = DaoUtils.readBoolean(map.get("master_present")); + masterIVREndpointSessionId = DaoUtils.readString(map.get("master_ivr_endpoint_session_id")); + masterBridgeEndpointId = DaoUtils.readString(map.get("master_bridge_endpoint_id")); + masterBridgeEndpointSessionId = DaoUtils.readString(map.get("master_bridge_endpoint_session_id")); + masterBridgeConnectionIdentifier = DaoUtils.readString(map.get("master_bridge_conn_id")); + masterIVRConnectionIdentifier = DaoUtils.readString(map.get("master_ivr_conn_id")); + moderatorPresent = DaoUtils.readBoolean(map.get("moderator_present")); + } catch (Exception e) {} + return new ConferenceDetailRecord(sid, dateCreated, dateUpdated, accountSid, status, friendlyName, apiVersion, uri, msId, masterConferenceEndpointId, masterPresent, masterIVREndpointId, masterIVREndpointSessionId, masterBridgeEndpointId, masterBridgeEndpointSessionId, masterBridgeConnectionIdentifier, masterIVRConnectionIdentifier, moderatorPresent); + } + + private Map toMap(final ConferenceDetailRecord cdr) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(cdr.getSid())); + map.put("date_created", DaoUtils.writeDateTime(cdr.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(cdr.getDateUpdated())); + map.put("account_sid", DaoUtils.writeSid(cdr.getAccountSid())); + map.put("status", cdr.getStatus()); + map.put("friendly_name", cdr.getFriendlyName()); + map.put("api_version", cdr.getApiVersion()); + map.put("uri", DaoUtils.writeUri(cdr.getUri())); + map.put("master_ms_id", cdr.getMasterMsId()); + map.put("master_conference_endpoint_id", cdr.getMasterConferenceEndpointId()); + map.put("master_ivr_endpoint_id", cdr.getMasterIVREndpointId()); + map.put("master_ivr_endpoint_session_id", cdr.getMasterIVREndpointSessionId()); + map.put("master_bridge_endpoint_id", cdr.getMasterBridgeEndpointId()); + map.put("master_bridge_endpoint_session_id", cdr.getMasterBridgeEndpointSessionId()); + map.put("master_present", cdr.isMasterPresent()); + map.put("master_bridge_conn_id", cdr.getMasterBridgeConnectionIdentifier()); + map.put("master_ivr_conn_id", cdr.getMasterIVRConnectionIdentifier()); + map.put("moderator_present", cdr.isModeratorPresent()); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisDaoManager.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisDaoManager.java new file mode 100644 index 0000000000..68327f1209 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisDaoManager.java @@ -0,0 +1,320 @@ +/* + * 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.dao.mybatis; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.Reader; +import java.util.Properties; + +import org.apache.commons.configuration.Configuration; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.restcomm.connect.commons.amazonS3.S3AccessTool; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.AnnouncementsDao; +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.AvailablePhoneNumbersDao; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.ConferenceDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.dao.GatewaysDao; +import org.restcomm.connect.dao.GeolocationDao; +import org.restcomm.connect.dao.HttpCookiesDao; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.InstanceIdDao; +import org.restcomm.connect.dao.MediaResourceBrokerDao; +import org.restcomm.connect.dao.MediaServersDao; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.OutgoingCallerIdsDao; +import org.restcomm.connect.dao.ProfilesDao; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.RegistrationsDao; +import org.restcomm.connect.dao.ShortCodesDao; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.dao.TranscriptionsDao; +import org.restcomm.connect.dao.UsageDao; + +import scala.concurrent.ExecutionContext; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisDaoManager implements DaoManager { + private Configuration configuration; + private Configuration amazonS3Configuration; + private Configuration runtimeConfiguration; + private S3AccessTool s3AccessTool; + private AccountsDao accountsDao; + private ApplicationsDao applicationsDao; + private AvailablePhoneNumbersDao availablePhoneNumbersDao; + private CallDetailRecordsDao callDetailRecordsDao; + private ConferenceDetailRecordsDao conferenceDetailRecordsDao; + private ClientsDao clientsDao; + private HttpCookiesDao httpCookiesDao; + private IncomingPhoneNumbersDao incomingPhoneNumbersDao; + private NotificationsDao notificationsDao; + private OutgoingCallerIdsDao outgoingCallerIdsDao; + private RegistrationsDao presenceRecordsDao; + private RecordingsDao recordingsDao; + private ShortCodesDao shortCodesDao; + private SmsMessagesDao smsMessagesDao; + private UsageDao usageDao; + private TranscriptionsDao transcriptionsDao; + private GatewaysDao gatewaysDao; + private AnnouncementsDao announcementsDao; + private InstanceIdDao instanceIdDao; + private MediaServersDao mediaServersDao; + private MediaResourceBrokerDao mediaResourceBrokerDao; + private ExtensionsConfigurationDao extensionsConfigurationDao; + private GeolocationDao geolocationDao; + private ProfileAssociationsDao profileAssociationsDao; + private OrganizationsDao organizationsDao; + private ProfilesDao profilesDao; + + private ExecutionContext ec; + + public MybatisDaoManager() { + super(); + } + + @Override + public void configure(final Configuration configuration, Configuration daoManagerConfiguration, final ExecutionContext ec) { + this.configuration = daoManagerConfiguration.subset("dao-manager"); + this.amazonS3Configuration = configuration.subset("amazon-s3"); + this.runtimeConfiguration = configuration.subset("runtime-settings"); + this.ec = ec; + } + + @Override + public AccountsDao getAccountsDao() { + return accountsDao; + } + + @Override + public ApplicationsDao getApplicationsDao() { + return applicationsDao; + } + + @Override + public AnnouncementsDao getAnnouncementsDao() { + return announcementsDao; + } + + @Override + public AvailablePhoneNumbersDao getAvailablePhoneNumbersDao() { + return availablePhoneNumbersDao; + } + + @Override + public CallDetailRecordsDao getCallDetailRecordsDao() { + return callDetailRecordsDao; + } + + @Override + public ConferenceDetailRecordsDao getConferenceDetailRecordsDao() { + return conferenceDetailRecordsDao; + } + + @Override + public ClientsDao getClientsDao() { + return clientsDao; + } + + @Override + public HttpCookiesDao getHttpCookiesDao() { + return httpCookiesDao; + } + + @Override + public IncomingPhoneNumbersDao getIncomingPhoneNumbersDao() { + return incomingPhoneNumbersDao; + } + + @Override + public NotificationsDao getNotificationsDao() { + return notificationsDao; + } + + @Override + public RegistrationsDao getRegistrationsDao() { + return presenceRecordsDao; + } + + @Override + public OutgoingCallerIdsDao getOutgoingCallerIdsDao() { + return outgoingCallerIdsDao; + } + + @Override + public RecordingsDao getRecordingsDao() { + return recordingsDao; + } + + @Override + public ShortCodesDao getShortCodesDao() { + return shortCodesDao; + } + + @Override + public SmsMessagesDao getSmsMessagesDao() { + return smsMessagesDao; + } + + @Override + public UsageDao getUsageDao() { + return usageDao; + } + + @Override + public TranscriptionsDao getTranscriptionsDao() { + return transcriptionsDao; + } + + @Override + public GatewaysDao getGatewaysDao() { + return gatewaysDao; + } + + @Override + public InstanceIdDao getInstanceIdDao() { + return instanceIdDao; + } + + @Override + public MediaServersDao getMediaServersDao() { + return mediaServersDao; + } + + @Override + public MediaResourceBrokerDao getMediaResourceBrokerDao() { + return mediaResourceBrokerDao; + } + + @Override + public ExtensionsConfigurationDao getExtensionsConfigurationDao() { + return extensionsConfigurationDao; + } + + @Override + public GeolocationDao getGeolocationDao() { + return geolocationDao; + } + + @Override + public ProfileAssociationsDao getProfileAssociationsDao() { + return profileAssociationsDao; + } + + @Override + public OrganizationsDao getOrganizationsDao() { + return organizationsDao; + } + + @Override + public ProfilesDao getProfilesDao() { + return profilesDao; + } + + @Override + public void shutdown() { + // Nothing to do. + } + + @Override + public void start() throws RuntimeException { + // This must be called before any other MyBatis methods. + org.apache.ibatis.logging.LogFactory.useSlf4jLogging(); + // Load the configuration file. + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final String path = configuration.getString("configuration-file"); + Reader reader = null; + try { + reader = new FileReader(path); + } catch (final FileNotFoundException exception) { + throw new RuntimeException(exception); + } + final Properties properties = new Properties(); + final String dataFiles = configuration.getString("data-files"); + final String sqlFiles = configuration.getString("sql-files"); + properties.setProperty("data", dataFiles); + properties.setProperty("sql", sqlFiles); + final SqlSessionFactory sessions = builder.build(reader, properties); + if(!amazonS3Configuration.isEmpty()) { // Do not fail with NPE is amazonS3Configuration is not present for older install + boolean amazonS3Enabled = amazonS3Configuration.getBoolean("enabled"); + if (amazonS3Enabled) { + final String accessKey = amazonS3Configuration.getString("access-key"); + final String securityKey = amazonS3Configuration.getString("security-key"); + final String bucketName = amazonS3Configuration.getString("bucket-name"); + final String folder = amazonS3Configuration.getString("folder"); + final boolean reducedRedundancy = amazonS3Configuration.getBoolean("reduced-redundancy"); + final int minutesToRetainPublicUrl = amazonS3Configuration.getInt("minutes-to-retain-public-url", 10); + final boolean removeOriginalFile = amazonS3Configuration.getBoolean("remove-original-file"); + final String bucketRegion = amazonS3Configuration.getString("bucket-region"); + final boolean testing = amazonS3Configuration.getBoolean("testing",false); + final String testingUrl = amazonS3Configuration.getString("testing-url",null); + s3AccessTool = new S3AccessTool(accessKey, securityKey, bucketName, folder, reducedRedundancy, minutesToRetainPublicUrl, removeOriginalFile,bucketRegion, testing, testingUrl); + } + } + start(sessions); + } + + public void start(final SqlSessionFactory sessions) { + // Instantiate the DAO objects. + accountsDao = new MybatisAccountsDao(sessions); + applicationsDao = new MybatisApplicationsDao(sessions); + announcementsDao = new MybatisAnnouncementsDao(sessions); + availablePhoneNumbersDao = new MybatisAvailablePhoneNumbersDao(sessions); + callDetailRecordsDao = new MybatisCallDetailRecordsDao(sessions); + conferenceDetailRecordsDao = new MybatisConferenceDetailRecordsDao(sessions); + clientsDao = new MybatisClientsDao(sessions); + httpCookiesDao = new MybatisHttpCookiesDao(sessions); + incomingPhoneNumbersDao = new MybatisIncomingPhoneNumbersDao(sessions); + notificationsDao = new MybatisNotificationsDao(sessions); + outgoingCallerIdsDao = new MybatisOutgoingCallerIdsDao(sessions); + presenceRecordsDao = new MybatisRegistrationsDao(sessions); + if (s3AccessTool != null) { + final String recordingPath = runtimeConfiguration.getString("recordings-path"); + recordingsDao = new MybatisRecordingsDao(sessions, s3AccessTool, recordingPath, ec); + } else { + recordingsDao = new MybatisRecordingsDao(sessions); + } + shortCodesDao = new MybatisShortCodesDao(sessions); + smsMessagesDao = new MybatisSmsMessagesDao(sessions); + usageDao = new MybatisUsageDao(sessions); + transcriptionsDao = new MybatisTranscriptionsDao(sessions); + gatewaysDao = new MybatisGatewaysDao(sessions); + instanceIdDao = new MybatisInstanceIdDao(sessions); + mediaServersDao = new MybatisMediaServerDao(sessions); + mediaResourceBrokerDao = new MybatisMediaResourceBrokerDao(sessions); + extensionsConfigurationDao = new MybatisExtensionsConfigurationDao(sessions); + geolocationDao = new MybatisGeolocationDao(sessions); + profileAssociationsDao = new MybatisProfileAssociationsDao(sessions); + organizationsDao = new MybatisOrganizationDao(sessions); + profilesDao = new MybatisProfilesDao(sessions); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java new file mode 100644 index 0000000000..e5dfb2f6ee --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java @@ -0,0 +1,368 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.dao.mybatis; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.io.IOUtils; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.joda.time.DateTimeComparator; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.api.ExtensionConfiguration; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.restcomm.connect.dao.DaoUtils.readBoolean; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; + +/** + * Created by gvagenas on 11/10/2016. + */ +public class MybatisExtensionsConfigurationDao implements ExtensionsConfigurationDao { + + private static Logger logger = Logger.getLogger(MybatisExtensionsConfigurationDao.class); + private static final String namespace = "org.restcomm.connect.dao.ExtensionsConfigurationDao."; + private final SqlSessionFactory sessions; + + public MybatisExtensionsConfigurationDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addConfiguration(ExtensionConfiguration extensionConfiguration) throws ConfigurationException { + final SqlSession session = sessions.openSession(); + try { + if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) { + if (validate(extensionConfiguration)) { + session.insert(namespace + "addConfiguration", toMap(extensionConfiguration)); + session.commit(); + } else { + throw new ConfigurationException("Exception trying to add new configuration, validation failed. configuration type: " + + extensionConfiguration.getConfigurationType()); + } + } + } finally { + session.close(); + } + } + + @Override + public void updateConfiguration(ExtensionConfiguration extensionConfiguration) throws ConfigurationException { + final SqlSession session = sessions.openSession(); + try { + if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) { + if (validate(extensionConfiguration)) { + session.update(namespace + "updateConfiguration", toMap(extensionConfiguration)); + } else { + throw new ConfigurationException("Exception trying to update configuration, validation failed. configuration type: " + + extensionConfiguration.getConfigurationType()); + } + } + session.commit(); + } finally { + session.close(); + } + } + + @Override + public ExtensionConfiguration getConfigurationByName(String extensionName) { + final SqlSession session = sessions.openSession(); + ExtensionConfiguration extensionConfiguration = null; + try { + final Map result = session.selectOne(namespace + "getConfigurationByName", extensionName); + if (result != null) { + extensionConfiguration = toExtensionConfiguration(result); + } + return extensionConfiguration; + } finally { + session.close(); + } + } + + @Override + public ExtensionConfiguration getConfigurationBySid(Sid extensionSid) { + final SqlSession session = sessions.openSession(); + ExtensionConfiguration extensionConfiguration = null; + try { + final Map result = session.selectOne(namespace + "getConfigurationBySid", extensionSid.toString()); + if (result != null) { + extensionConfiguration = toExtensionConfiguration(result); + } + return extensionConfiguration; + } finally { + session.close(); + } + } + + @Override + public List getAllConfiguration() { + final SqlSession session = sessions.openSession(); + ExtensionConfiguration extensionConfiguration = null; + try { + final List> results = session.selectList(namespace + "getAllConfiguration"); + final List confs = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + confs.add(toExtensionConfiguration(result)); + } + } + return confs; + } finally { + session.close(); + } + } + + @Override + public void deleteConfigurationByName(String extensionName) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "deleteConfigurationByName", extensionName); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void deleteConfigurationBySid(Sid extensionSid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "deleteConfigurationBySid", extensionSid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public boolean isLatestVersionByName(String extensionName, DateTime dateTime) { + final SqlSession session = sessions.openSession(); + boolean result = false; + int comp; + try { + final DateTime dateUpdated = new DateTime(session.selectOne(namespace + "getDateUpdatedByName", extensionName)); + if (dateUpdated != null) { + comp = DateTimeComparator.getInstance().compare(dateTime, dateUpdated); + if (comp < 0) { + //Negative value means that given dateTime is less than dateUpdated, which means that DB + //has a newer cnfiguration + result = true; + } + } + + } finally { + session.close(); + } + return result; + } + + @Override + public boolean isLatestVersionBySid(Sid extensionSid, DateTime dateTime) { + final SqlSession session = sessions.openSession(); + boolean result = false; + int comp; + try { + final DateTime dateUpdated = new DateTime(session.selectOne(namespace + "getDateUpdatedBySid", extensionSid.toString())); + if (dateUpdated != null) { + comp = DateTimeComparator.getInstance().compare(dateTime, dateUpdated); + if (comp < 0) { + //Negative value means that given dateTime is less than dateUpdated, which means that DB + //has a newer cnfiguration + result = true; + } + } + + } finally { + session.close(); + } + return result; + } + + @Override + public boolean validate(ExtensionConfiguration extensionConfiguration) { + ExtensionConfiguration.configurationType configurationType = extensionConfiguration.getConfigurationType(); + if (configurationType.equals(ExtensionConfiguration.configurationType.JSON)) { + Gson gson = new Gson(); + try { + Object o = gson.fromJson((String) extensionConfiguration.getConfigurationData(), Object.class); + String json = new GsonBuilder().setPrettyPrinting().create().toJson(o); + return (json != null || !json.isEmpty()); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("invalid json format, exception: "+e); + } + } finally { + gson = null; + } + } else if (configurationType.equals(ExtensionConfiguration.configurationType.XML)) { + Configuration xml = null; + try { + XMLConfiguration xmlConfiguration = new XMLConfiguration(); + xmlConfiguration.setDelimiterParsingDisabled(true); + xmlConfiguration.setAttributeSplittingDisabled(true); + InputStream is = IOUtils.toInputStream(extensionConfiguration.getConfigurationData().toString()); + xmlConfiguration.load(is); + xml = xmlConfiguration; + return (xml != null || !xml.isEmpty()); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("invalid xml document, exception: "+e); + } + } finally { + xml = null; + } + } + return false; + } + + private ExtensionConfiguration toExtensionConfiguration(final Map map) { + final Sid sid = new Sid((String)map.get("sid")); + final String extension = (String) map.get("extension"); + boolean enabled = true; + if (readBoolean(map.get("enabled")) != null) + enabled = readBoolean(map.get("enabled")); + final Object confData = map.get("configuration_data"); + final ExtensionConfiguration.configurationType confType = + ExtensionConfiguration.configurationType.valueOf((String)map.get("configuration_type")); + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + return new ExtensionConfiguration(sid, extension, enabled, confData, confType, dateCreated, dateUpdated); + } + + private ExtensionConfiguration toAccountsExtensionConfiguration(final Map map) { + final Sid sid = new Sid((String)map.get("extension")); + final String extension = (String) map.get("extension"); + final Object confData = map.get("configuration_data"); + return new ExtensionConfiguration(sid, extension, true, confData, null, null, null); + } + + private Map toMap(final ExtensionConfiguration extensionConfiguration) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(extensionConfiguration.getSid())); + map.put("extension", extensionConfiguration.getExtensionName()); + + if (extensionConfiguration.getConfigurationData() != null) + map.put("configuration_data", extensionConfiguration.getConfigurationData()); + if (extensionConfiguration.getConfigurationType() != null) + map.put("configuration_type", extensionConfiguration.getConfigurationType().toString()); + if (extensionConfiguration.getDateCreated() != null) + map.put("date_created", DaoUtils.writeDateTime(extensionConfiguration.getDateCreated())); + if (extensionConfiguration.getDateUpdated() != null) + map.put("date_updated", DaoUtils.writeDateTime(extensionConfiguration.getDateUpdated())); + + map.put("enabled", extensionConfiguration.isEnabled()); + return map; + } + + @Override + public ExtensionConfiguration getAccountExtensionConfiguration(String accountSid, String extensionSid) { + final SqlSession session = sessions.openSession(); + ExtensionConfiguration extensionConfiguration = null; + try { + Map params = new HashMap(); + params.put("account_sid", accountSid.toString()); + params.put("extension_sid", extensionSid.toString()); + final Map result = session.selectOne(namespace + "getAccountExtensionConfiguration", params); + if (result != null) { + extensionConfiguration = toAccountsExtensionConfiguration(result); + } + return extensionConfiguration; + } finally { + session.close(); + } + } + + @Override + public void addAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException { + final SqlSession session = sessions.openSession(); + try { + if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) { + if (validate(extensionConfiguration)) { + final Map map = new HashMap(); + map.put("account_sid", DaoUtils.writeSid(accountSid)); + map.put("extension_sid", DaoUtils.writeSid(extensionConfiguration.getSid())); + + if (extensionConfiguration.getConfigurationData() != null) + map.put("configuration_data", extensionConfiguration.getConfigurationData()); + + session.insert(namespace + "addAccountExtensionConfiguration", map); + session.commit(); + } else { + throw new ConfigurationException("Exception trying to add new configuration, validation failed. configuration type: " + + extensionConfiguration.getConfigurationType()); + } + } + } finally { + session.close(); + } + } + + @Override + public void updateAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) + throws ConfigurationException { + final SqlSession session = sessions.openSession(); + try { + if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) { + if (validate(extensionConfiguration)) { + final Map map = new HashMap(); + map.put("account_sid", DaoUtils.writeSid(accountSid)); + map.put("extension_sid", DaoUtils.writeSid(extensionConfiguration.getSid())); + + if (extensionConfiguration.getConfigurationData() != null) + map.put("configuration_data", extensionConfiguration.getConfigurationData()); + session.update(namespace + "updateAccountExtensionConfiguration", map); + } else { + throw new ConfigurationException("Exception trying to update configuration, validation failed. configuration type: " + + extensionConfiguration.getConfigurationType()); + } + } + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void deleteAccountExtensionConfiguration(String accountSid, String extensionSid) { + final SqlSession session = sessions.openSession(); + try { + Map params = new HashMap(); + params.put("account_sid", accountSid.toString()); + params.put("extension_sid", extensionSid.toString()); + session.delete(namespace + "deleteAccountExtensionConfiguration", params); + session.commit(); + } finally { + session.close(); + } + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisGatewaysDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGatewaysDao.java similarity index 75% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisGatewaysDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGatewaysDao.java index cf729103a4..abd88b7db0 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisGatewaysDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGatewaysDao.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.net.URI; import java.util.ArrayList; @@ -30,11 +30,11 @@ import org.joda.time.DateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.GatewaysDao; -import org.mobicents.servlet.restcomm.entities.Gateway; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.GatewaysDao; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -115,31 +115,31 @@ public void updateGateway(final Gateway gateway) { } private Gateway toGateway(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String friendlName = readString(map.get("friendly_name")); - final String password = readString(map.get("password")); - final String proxy = readString(map.get("proxy")); - final Boolean register = readBoolean(map.get("register")); - final String userAgent = readString(map.get("user_name")); - final Integer timeToLive = readInteger(map.get("ttl")); - final URI uri = readUri(map.get("uri")); + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final String friendlName = DaoUtils.readString(map.get("friendly_name")); + final String password = DaoUtils.readString(map.get("password")); + final String proxy = DaoUtils.readString(map.get("proxy")); + final Boolean register = DaoUtils.readBoolean(map.get("register")); + final String userAgent = DaoUtils.readString(map.get("user_name")); + final Integer timeToLive = DaoUtils.readInteger(map.get("ttl")); + final URI uri = DaoUtils.readUri(map.get("uri")); return new Gateway(sid, dateCreated, dateUpdated, friendlName, password, proxy, register, userAgent, timeToLive, uri); } private Map toMap(final Gateway gateway) { final Map map = new HashMap(); - map.put("sid", writeSid(gateway.getSid())); - map.put("date_created", writeDateTime(gateway.getDateCreated())); - map.put("date_updated", writeDateTime(gateway.getDateUpdated())); + map.put("sid", DaoUtils.writeSid(gateway.getSid())); + map.put("date_created", DaoUtils.writeDateTime(gateway.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(gateway.getDateUpdated())); map.put("friendly_name", gateway.getFriendlyName()); map.put("password", gateway.getPassword()); map.put("proxy", gateway.getProxy()); map.put("register", gateway.register()); map.put("user_name", gateway.getUserName()); map.put("ttl", gateway.getTimeToLive()); - map.put("uri", writeUri(gateway.getUri())); + map.put("uri", DaoUtils.writeUri(gateway.getUri())); return map; } } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGeolocationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGeolocationDao.java new file mode 100644 index 0000000000..5c8d64f3a2 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisGeolocationDao.java @@ -0,0 +1,213 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao.mybatis; + +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readInteger; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; +import static org.restcomm.connect.dao.DaoUtils.readGeolocationType; +import static org.restcomm.connect.dao.DaoUtils.readLong; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.dao.GeolocationDao; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author Fernando Mendioroz + * + */ +public class MybatisGeolocationDao implements GeolocationDao { + + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.GeolocationDao."; + private final SqlSessionFactory sessions; + + public MybatisGeolocationDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addGeolocation(Geolocation gl) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addGeolocation", toMap(gl)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Geolocation getGeolocation(Sid sid) { + return getGeolocation(namespace + "getGeolocation", sid.toString()); + } + + private Geolocation getGeolocation(final String selector, final String parameter) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(selector, parameter); + if (result != null) { + return toGeolocation(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getGeolocations(Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getGeolocations", accountSid.toString()); + final List geolocations = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + geolocations.add(toGeolocation(result)); + } + } + return geolocations; + } finally { + session.close(); + } + } + + @Override + public void removeGeolocation(Sid sid) { + removeGeolocations(namespace + "removeGeolocation", sid); + } + + @Override + public void removeGeolocations(final Sid accountSid) { + removeGeolocations(namespace + "removeGeolocations", accountSid); + } + + private void removeGeolocations(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateGeolocation(Geolocation gl) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateGeolocation", toMap(gl)); + session.commit(); + } finally { + session.close(); + } + } + + private Map toMap(Geolocation gl) { + final Map map = new HashMap(); + map.put("sid", writeSid(gl.getSid())); + map.put("date_created", writeDateTime(gl.getDateCreated())); + map.put("date_updated", writeDateTime(gl.getDateUpdated())); + map.put("date_executed", writeDateTime(gl.getDateExecuted())); + map.put("account_sid", writeSid(gl.getAccountSid())); + map.put("source", gl.getSource()); + map.put("device_identifier", gl.getDeviceIdentifier()); + map.put("geolocation_type", gl.getGeolocationType()); + map.put("response_status", gl.getResponseStatus()); + map.put("cell_id", gl.getCellId()); + map.put("location_area_code", gl.getLocationAreaCode()); + map.put("mobile_country_code", gl.getMobileCountryCode()); + map.put("mobile_network_code", gl.getMobileNetworkCode()); + map.put("network_entity_address", gl.getNetworkEntityAddress()); + map.put("age_of_location_info", gl.getAgeOfLocationInfo()); + map.put("device_latitude", gl.getDeviceLatitude()); + map.put("device_longitude", gl.getDeviceLongitude()); + map.put("accuracy", gl.getAccuracy()); + map.put("physical_address", gl.getPhysicalAddress()); + map.put("internet_address", gl.getInternetAddress()); + map.put("formatted_address", gl.getFormattedAddress()); + map.put("location_timestamp", writeDateTime(gl.getLocationTimestamp())); + map.put("event_geofence_latitude", gl.getEventGeofenceLatitude()); + map.put("event_geofence_longitude", gl.getEventGeofenceLongitude()); + map.put("radius", gl.getRadius()); + map.put("geolocation_positioning_type", gl.getGeolocationPositioningType()); + map.put("last_geolocation_response", gl.getLastGeolocationResponse()); + map.put("cause", gl.getCause()); + map.put("api_version", gl.getApiVersion()); + map.put("uri", writeUri(gl.getUri())); + return map; + } + + private Geolocation toGeolocation(final Map map) { + final Sid sid = readSid(map.get("sid")); + final DateTime date_created = readDateTime(map.get("date_created")); + final DateTime date_updated = readDateTime(map.get("date_updated")); + final DateTime date_executed = readDateTime(map.get("date_executed")); + final Sid account_sid = readSid(map.get("account_sid")); + final String source = readString(map.get("source")); + final String device_identifier = readString(map.get("device_identifier")); + final Geolocation.GeolocationType geolocation_type = readGeolocationType(map.get("geolocation_type")); + final String response_status = readString(map.get("response_status")); + final String cell_id = readString(map.get("cell_id")); + final String location_area_code = readString(map.get("location_area_code")); + final Integer mobile_country_code = readInteger(map.get("mobile_country_code")); + final String mobile_network_code = readString(map.get("mobile_network_code")); + final Long network_entity_address = readLong(map.get("network_entity_address")); + final Integer age_of_location_info = readInteger(map.get("age_of_location_info")); + final String device_latitude = readString(map.get("device_latitude")); + final String device_longitude = readString(map.get("device_longitude")); + final Long accuracy = readLong(map.get("accuracy")); + final String physical_address = readString(map.get("physical_address")); + final String internet_address = readString(map.get("internet_address")); + final String formatted_address = readString(map.get("formatted_address")); + final DateTime location_timestamp = readDateTime(map.get("location_timestamp")); + final String event_geofence_latitude = readString(map.get("event_geofence_latitude")); + final String event_geofence_longitude = readString(map.get("event_geofence_longitude")); + final Long radius = readLong(map.get("radius")); + final String geolocation_positioning_type = readString(map.get("geolocation_positioning_type")); + final String last_geolocation_response = readString(map.get("last_geolocation_response")); + final String cause = readString(map.get("cause")); + final String api_version = readString(map.get("api_version")); + final URI uri = readUri(map.get("uri")); + return new Geolocation(sid, date_created, date_updated, date_executed, account_sid, source, device_identifier, + geolocation_type, response_status, cell_id, location_area_code, mobile_country_code, mobile_network_code, + network_entity_address, age_of_location_info, device_latitude, device_longitude, accuracy, physical_address, + internet_address, formatted_address, location_timestamp, event_geofence_latitude, event_geofence_longitude, radius, + geolocation_positioning_type, last_geolocation_response, cause, api_version, uri); + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisHttpCookiesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisHttpCookiesDao.java similarity index 89% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisHttpCookiesDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisHttpCookiesDao.java index 1a3c7c789b..3311b3daa8 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisHttpCookiesDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisHttpCookiesDao.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.util.ArrayList; import java.util.Date; @@ -30,9 +30,9 @@ import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.HttpCookiesDao; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.HttpCookiesDao; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -139,13 +139,13 @@ public void updateCookie(final Sid sid, final Cookie cookie) { } private Cookie toCookie(final Map map) { - final String comment = readString(map.get("comment")); - final String domain = readString(map.get("domain")); + final String comment = DaoUtils.readString(map.get("comment")); + final String domain = DaoUtils.readString(map.get("domain")); final Date expirationDate = (Date) map.get("expiration_date"); - final String name = readString(map.get("name")); - final String path = readString(map.get("path")); - final String value = readString(map.get("value")); - final int version = readInteger(map.get("version")); + final String name = DaoUtils.readString(map.get("name")); + final String path = DaoUtils.readString(map.get("path")); + final String value = DaoUtils.readString(map.get("value")); + final int version = DaoUtils.readInteger(map.get("version")); final BasicClientCookie cookie = new BasicClientCookie(name, value); cookie.setComment(comment); cookie.setDomain(domain); @@ -157,7 +157,7 @@ private Cookie toCookie(final Map map) { private Map toMap(final Sid sid, final Cookie cookie) { final Map map = new HashMap(); - map.put("sid", writeSid(sid)); + map.put("sid", DaoUtils.writeSid(sid)); map.put("comment", cookie.getComment()); map.put("domain", cookie.getDomain()); map.put("expiration_date", cookie.getExpiryDate()); diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisIncomingPhoneNumbersDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisIncomingPhoneNumbersDao.java new file mode 100644 index 0000000000..8d4d7a9c1d --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisIncomingPhoneNumbersDao.java @@ -0,0 +1,280 @@ +/* + * 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.dao.mybatis; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.SearchFilterMode; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author jean.deruelle@telestax.com + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisIncomingPhoneNumbersDao implements IncomingPhoneNumbersDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.IncomingPhoneNumbersDao."; + private final SqlSessionFactory sessions; + private final Logger logger = Logger.getLogger(MybatisIncomingPhoneNumbersDao.class.getName()); + private static final String ORG_SID = "organization_sid"; + private static final String PHONE_NUM = "phone_number"; + + + public MybatisIncomingPhoneNumbersDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addIncomingPhoneNumber(final IncomingPhoneNumber incomingPhoneNumber) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addIncomingPhoneNumber", toMap(incomingPhoneNumber)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public IncomingPhoneNumber getIncomingPhoneNumber(final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getIncomingPhoneNumber", sid.toString()); + if (result != null) { + return toIncomingPhoneNumber(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getIncomingPhoneNumbers(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getIncomingPhoneNumbers", + accountSid.toString()); + final List incomingPhoneNumbers = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + incomingPhoneNumbers.add(toIncomingPhoneNumber(result)); + } + } + return incomingPhoneNumbers; + } finally { + session.close(); + } + } + + @Override + public List getIncomingPhoneNumbersRegex(IncomingPhoneNumberFilter incomingPhoneNumberFilter) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getIncomingPhoneNumbersRegex", incomingPhoneNumberFilter); + final List incomingPhoneNumbers = new ArrayList(results.size()); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + incomingPhoneNumbers.add(toIncomingPhoneNumber(result)); + } + } + return incomingPhoneNumbers; + } finally { + session.close(); + } + } + + + + @Override + public List getIncomingPhoneNumbersByFilter(IncomingPhoneNumberFilter filter) { + final SqlSession session = sessions.openSession(); + try { + + String query = "getIncomingPhoneNumbersByFriendlyName"; + if (filter.getFilterMode().equals(SearchFilterMode.WILDCARD_MATCH)) { + query = "searchNumbersWithWildcardMode"; + } + + final List> results = session.selectList(namespace + query, + filter); + final List incomingPhoneNumbers = new ArrayList(results.size()); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + incomingPhoneNumbers.add(toIncomingPhoneNumber(result)); + } + } + return incomingPhoneNumbers; + } finally { + session.close(); + } + } + + @Override + public void removeIncomingPhoneNumber(final Sid sid) { + removeIncomingPhoneNumbers("removeIncomingPhoneNumber", sid); + } + + @Override + public void removeIncomingPhoneNumbers(final Sid accountSid) { + removeIncomingPhoneNumbers("removeIncomingPhoneNumbers", accountSid); + } + + private void removeIncomingPhoneNumbers(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateIncomingPhoneNumber(final IncomingPhoneNumber incomingPhoneNumber) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateIncomingPhoneNumber", toMap(incomingPhoneNumber)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Integer getTotalIncomingPhoneNumbers(IncomingPhoneNumberFilter filter) { + + try (final SqlSession session = sessions.openSession();) { + final Integer total = session.selectOne(namespace + "getTotalIncomingPhoneNumbersByUsingFilters", filter); + return total; + } + } + + private IncomingPhoneNumber toIncomingPhoneNumber(final Map map) { + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final String friendlyName = DaoUtils.readString(map.get("friendly_name")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String phoneNumber = DaoUtils.readString(map.get(PHONE_NUM)); + final String apiVersion = DaoUtils.readString(map.get("api_version")); + final Boolean hasVoiceCallerIdLookup = DaoUtils.readBoolean(map.get("voice_caller_id_lookup")); + final URI voiceUrl = DaoUtils.readUri(map.get("voice_url")); + final String voiceMethod = DaoUtils.readString(map.get("voice_method")); + final URI voiceFallbackUrl = DaoUtils.readUri(map.get("voice_fallback_url")); + final String voiceFallbackMethod = DaoUtils.readString(map.get("voice_fallback_method")); + final URI statusCallback = DaoUtils.readUri(map.get("status_callback")); + final String statusCallbackMethod = DaoUtils.readString(map.get("status_callback_method")); + final Sid voiceApplicationSid = DaoUtils.readSid(map.get("voice_application_sid")); + final URI smsUrl = DaoUtils.readUri(map.get("sms_url")); + final String smsMethod = DaoUtils.readString(map.get("sms_method")); + final URI smsFallbackUrl = DaoUtils.readUri(map.get("sms_fallback_url")); + final String smsFallbackMethod = DaoUtils.readString(map.get("sms_fallback_method")); + final Sid smsApplicationSid = DaoUtils.readSid(map.get("sms_application_sid")); + final URI uri = DaoUtils.readUri(map.get("uri")); + final URI ussdUrl = DaoUtils.readUri(map.get("ussd_url")); + final String ussdMethod = DaoUtils.readString(map.get("ussd_method")); + final URI ussdFallbackUrl = DaoUtils.readUri(map.get("ussd_fallback_url")); + final String ussdFallbackMethod = DaoUtils.readString(map.get("ussd_fallback_method")); + final Sid ussdApplicationSid = DaoUtils.readSid(map.get("ussd_application_sid")); + final URI referUrl = DaoUtils.readUri(map.get("refer_url")); + final String referMethod = DaoUtils.readString(map.get("refer_method")); + final Sid referApplicationSid = DaoUtils.readSid(map.get("refer_application_sid")); + final Sid organizationSid = DaoUtils.readSid(map.get(ORG_SID)); + + + final Boolean voiceCapable = DaoUtils.readBoolean(map.get("voice_capable")); + final Boolean smsCapable = DaoUtils.readBoolean(map.get("sms_capable")); + final Boolean mmsCapable = DaoUtils.readBoolean(map.get("mms_capable")); + final Boolean faxCapable = DaoUtils.readBoolean(map.get("fax_capable")); + final Boolean pureSip = DaoUtils.readBoolean(map.get("pure_sip")); + final String cost = DaoUtils.readString(map.get("cost")); + // foreign properties loaded from applications table + final String voiceApplicationName = DaoUtils.readString(map.get("voice_application_name")); + final String smsApplicationName = DaoUtils.readString(map.get("sms_application_name")); + final String ussdApplicationName = DaoUtils.readString(map.get("ussd_application_name")); + final String referApplicationName = DaoUtils.readString(map.get("refer_application_name")); + + return new IncomingPhoneNumber(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, cost, apiVersion, + hasVoiceCallerIdLookup, voiceUrl, voiceMethod, voiceFallbackUrl, voiceFallbackMethod, statusCallback, + statusCallbackMethod, voiceApplicationSid, smsUrl, smsMethod, smsFallbackUrl, smsFallbackMethod, + smsApplicationSid, uri, ussdUrl, ussdMethod, ussdFallbackUrl, ussdFallbackMethod, ussdApplicationSid, + referUrl, referMethod, referApplicationSid, + voiceCapable, smsCapable, mmsCapable, faxCapable, pureSip, voiceApplicationName, smsApplicationName, ussdApplicationName, referApplicationName, organizationSid); + } + + private Map toMap(final IncomingPhoneNumber incomingPhoneNumber) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(incomingPhoneNumber.getSid())); + map.put("date_created", DaoUtils.writeDateTime(incomingPhoneNumber.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(incomingPhoneNumber.getDateUpdated())); + map.put("friendly_name", incomingPhoneNumber.getFriendlyName()); + map.put("account_sid", DaoUtils.writeSid(incomingPhoneNumber.getAccountSid())); + map.put(PHONE_NUM, incomingPhoneNumber.getPhoneNumber()); + map.put("api_version", incomingPhoneNumber.getApiVersion()); + map.put("voice_caller_id_lookup", incomingPhoneNumber.hasVoiceCallerIdLookup()); + map.put("voice_url", DaoUtils.writeUri(incomingPhoneNumber.getVoiceUrl())); + map.put("voice_method", incomingPhoneNumber.getVoiceMethod()); + map.put("voice_fallback_url", DaoUtils.writeUri(incomingPhoneNumber.getVoiceFallbackUrl())); + map.put("voice_fallback_method", incomingPhoneNumber.getVoiceFallbackMethod()); + map.put("status_callback", DaoUtils.writeUri(incomingPhoneNumber.getStatusCallback())); + map.put("status_callback_method", incomingPhoneNumber.getStatusCallbackMethod()); + map.put("voice_application_sid", DaoUtils.writeSid(incomingPhoneNumber.getVoiceApplicationSid())); + map.put("sms_url", DaoUtils.writeUri(incomingPhoneNumber.getSmsUrl())); + map.put("sms_method", incomingPhoneNumber.getSmsMethod()); + map.put("sms_fallback_url", DaoUtils.writeUri(incomingPhoneNumber.getSmsFallbackUrl())); + map.put("sms_fallback_method", incomingPhoneNumber.getSmsFallbackMethod()); + map.put("sms_application_sid", DaoUtils.writeSid(incomingPhoneNumber.getSmsApplicationSid())); + map.put("uri", DaoUtils.writeUri(incomingPhoneNumber.getUri())); + map.put("ussd_url", DaoUtils.writeUri(incomingPhoneNumber.getUssdUrl())); + map.put("ussd_method", incomingPhoneNumber.getUssdMethod()); + map.put("ussd_fallback_url", DaoUtils.writeUri(incomingPhoneNumber.getUssdFallbackUrl())); + map.put("ussd_fallback_method", incomingPhoneNumber.getUssdFallbackMethod()); + map.put("ussd_application_sid", DaoUtils.writeSid(incomingPhoneNumber.getUssdApplicationSid())); + map.put("refer_url", DaoUtils.writeUri(incomingPhoneNumber.getReferUrl())); + map.put("refer_method", incomingPhoneNumber.getReferMethod()); + map.put("refer_application_sid", DaoUtils.writeSid(incomingPhoneNumber.getReferApplicationSid())); + map.put("voice_capable", incomingPhoneNumber.isVoiceCapable()); + map.put("sms_capable", incomingPhoneNumber.isSmsCapable()); + map.put("mms_capable", incomingPhoneNumber.isMmsCapable()); + map.put("fax_capable", incomingPhoneNumber.isFaxCapable()); + map.put("pure_sip", incomingPhoneNumber.isPureSip()); + map.put("cost", incomingPhoneNumber.getCost()); + map.put(ORG_SID, DaoUtils.writeSid(incomingPhoneNumber.getOrganizationSid())); + return map; + } + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisInstanceIdDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisInstanceIdDao.java new file mode 100644 index 0000000000..120873dade --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisInstanceIdDao.java @@ -0,0 +1,138 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.InstanceIdDao; +import org.restcomm.connect.dao.entities.InstanceId; +import org.restcomm.connect.commons.dao.Sid; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; + +/** + * @author gvagenas + * + */ +@ThreadSafe +public class MybatisInstanceIdDao implements InstanceIdDao{ + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.InstanceIdDao."; + private final SqlSessionFactory sessions; + + public MybatisInstanceIdDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public InstanceId getInstanceId() { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace+"getInstanceId"); + if (result != null) { + return toInstanceId(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public InstanceId getInstanceIdByHost(String host) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace+"getInstanceIdByHost", host); + if (result != null) { + return toInstanceId(result); + } else { + return null; + } + } catch (Exception e) { + session.close(); + return getInstanceId(); + } finally { + session.close(); + } + } + + @Override + public void addInstancecId(InstanceId instanceId) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addInstanceId", toMap(instanceId)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateInstanceId(InstanceId instanceId) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateInstanceId", toMap(instanceId)); + session.commit(); + } finally { + session.close(); + } + } + + private InstanceId toInstanceId(Map map) { + final Sid sid = readSid(map.get("instance_id")); + String host = readString(map.get("host")); + if (host == null || host.isEmpty()) { + try { + host = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) {} + } + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + return new InstanceId(sid, host, dateCreated, dateUpdated); + } + + private Map toMap(final InstanceId instanceId) { + final Map map = new HashMap(); + map.put("instance_id", writeSid(instanceId.getId())); + String host = instanceId.getHost(); + if (host == null || host.isEmpty()) { + try { + host = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) {} + } + map.put("host", host); + map.put("date_created", writeDateTime(instanceId.getDateCreated())); + map.put("date_updated", writeDateTime(instanceId.getDateUpdated())); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaResourceBrokerDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaResourceBrokerDao.java new file mode 100644 index 0000000000..096208bc77 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaResourceBrokerDao.java @@ -0,0 +1,139 @@ +/* + * 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.dao.mybatis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.MediaResourceBrokerDao; +import org.restcomm.connect.dao.entities.MediaResourceBrokerEntity; +import org.restcomm.connect.dao.entities.MediaResourceBrokerEntityFilter; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisMediaResourceBrokerDao implements MediaResourceBrokerDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.MediaResourceBrokerDao."; + private final SqlSessionFactory sessions; + + public MybatisMediaResourceBrokerDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addMediaResourceBrokerEntity(MediaResourceBrokerEntity ms) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addMediaResourceBrokerEntity", toMap(ms)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateMediaResource(MediaResourceBrokerEntity ms) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "updateMediaResource", toMap(ms)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public List getMediaResourceBrokerEntities() { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getMediaServers"); + final List mList = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + mList.add(toMRBEntity(result)); + } + } + return mList; + } finally { + session.close(); + } + } + + @Override + public List getConnectedSlaveEntitiesByConfSid(Sid conferenceSid) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getConnectedSlaveEntitiesByConfSid", + conferenceSid.toString()); + final List entities = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + entities.add(toMRBEntity(result)); + } + } + return entities; + } finally { + session.close(); + } + } + + @Override + public void removeMediaResourceBrokerEntity(MediaResourceBrokerEntityFilter filter) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "removeMediaResourceBrokerEntity", filter); + session.commit(); + } finally { + session.close(); + } + } + + private MediaResourceBrokerEntity toMRBEntity(final Map map) { + final Sid conferenceSid = DaoUtils.readSid(map.get("conference_sid")); + final String slaveMsId = DaoUtils.readString(map.get("slave_ms_id")); + final String slaveMsBridgeEpId = DaoUtils.readString(map.get("slave_ms_bridge_ep_id")); + final String slaveMsCnfEpId = DaoUtils.readString(map.get("slave_ms_cnf_ep_id")); + final boolean isBridgedTogether = DaoUtils.readBoolean(map.get("is_bridged_together")); + + return new MediaResourceBrokerEntity(conferenceSid, slaveMsId, slaveMsBridgeEpId, slaveMsCnfEpId, isBridgedTogether); + } + + private Map toMap(final MediaResourceBrokerEntity ms) { + final Map map = new HashMap(); + map.put("conference_sid", DaoUtils.writeSid(ms.getConferenceSid())); + map.put("slave_ms_id", ms.getSlaveMsId()); + map.put("slave_ms_bridge_ep_id", ms.getSlaveMsBridgeEpId()); + map.put("slave_ms_cnf_ep_id", ms.getSlaveMsCnfEpId()); + map.put("is_bridged_together", ms.isBridgedTogether()); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaServerDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaServerDao.java new file mode 100644 index 0000000000..26e1327a1e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisMediaServerDao.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.dao.mybatis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.MediaServersDao; +import org.restcomm.connect.dao.entities.MediaServerEntity; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisMediaServerDao implements MediaServersDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.MediaServersDao."; + private final SqlSessionFactory sessions; + + public MybatisMediaServerDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addMediaServer(final MediaServerEntity ms) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addMediaServer", toMap(ms)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateMediaServer(final MediaServerEntity ms) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "updateMediaServer", toMap(ms)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public List getMediaServerEntityByIP(final String msIPAddress) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getMediaServerEntityByIP", msIPAddress); + final List msList = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + msList.add(toMediaServer(result)); + } + } + return msList; + } finally { + session.close(); + } + } + + @Override + public List getMediaServers() { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getMediaServers"); + final List msList = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + msList.add(toMediaServer(result)); + } + } + return msList; + } finally { + session.close(); + } + } + + @Override + public MediaServerEntity getMediaServer(String msId) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getMediaServer", msId); + if (result != null) { + return toMediaServer(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public void removeMediaServerEntity(String msId) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "removeMediaServerEntity", msId); + session.commit(); + } finally { + session.close(); + } + } + + private MediaServerEntity toMediaServer(final Map map) { + final int msId = DaoUtils.readInteger(map.get("ms_id")); + final String compatibility = DaoUtils.readString(map.get("compatibility")); + final String localIpAddress = DaoUtils.readString(map.get("local_ip")); + final int localPort = DaoUtils.readInteger(map.get("local_port")); + final String remoteIpAddress = DaoUtils.readString(map.get("remote_ip")); + final int remotePort = DaoUtils.readInteger(map.get("remote_port")); + final String responseTimeout = DaoUtils.readString(map.get("response_timeout")); + final String externalAddress = DaoUtils.readString(map.get("external_address")); + + return new MediaServerEntity(msId, compatibility, localIpAddress, localPort, remoteIpAddress, remotePort, responseTimeout, externalAddress); + } + + private Map toMap(final MediaServerEntity ms) { + final Map map = new HashMap(); + map.put("ms_id", ms.getMsId()); + map.put("compatibility", ms.getCompatibility()); + map.put("local_ip", ms.getLocalIpAddress()); + map.put("local_port", ms.getLocalPort()); + map.put("remote_ip", ms.getRemoteIpAddress()); + map.put("remote_port", ms.getRemotePort()); + map.put("response_timeout", ms.getResponseTimeout()); + map.put("external_address", ms.getExternalAddress()); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisNotificationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisNotificationsDao.java similarity index 80% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisNotificationsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisNotificationsDao.java index d5713b223c..e6d8cbf94e 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisNotificationsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisNotificationsDao.java @@ -17,7 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.commons.dao.Sid; import java.net.URI; import java.util.ArrayList; @@ -25,16 +33,15 @@ import java.util.List; import java.util.Map; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; - -import org.joda.time.DateTime; - -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readInteger; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; +import org.restcomm.connect.dao.entities.NotificationFilter; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -80,6 +87,38 @@ public List getNotifications(final Sid accountSid) { return getNotifications(namespace + "getNotifications", accountSid.toString()); } + @Override + public List getNotifications(NotificationFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getNotificationsByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toNotification(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public Integer getTotalNotification(NotificationFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalNotificationByUsingFilters", filter); + return total; + } finally { + session.close(); + } + } + @Override public List getNotificationsByCall(final Sid callSid) { return getNotifications(namespace + "getNotificationsByCall", callSid.toString()); diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOrganizationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOrganizationDao.java new file mode 100644 index 0000000000..99579db03b --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOrganizationDao.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.dao.mybatis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.entities.Organization; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisOrganizationDao implements OrganizationsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.OrganizationsDao."; + private final SqlSessionFactory sessions; + + public MybatisOrganizationDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addOrganization(final Organization organization) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addOrganization", toMap(organization)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Organization getOrganization(Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getOrganization", sid.toString()); + if (result != null) { + return toOrganization(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public Organization getOrganizationByDomainName(String domainName) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getOrganizationByDomainName", domainName); + if (result != null) { + return toOrganization(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getOrganizationsByStatus(Organization.Status status) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getOrganizationsByStatus", status.toString()); + final List organization = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + organization.add(toOrganization(result)); + } + } + return organization; + } finally { + session.close(); + } + } + + @Override + public List getAllOrganizations() { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getAllOrganizations"); + final List organization = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + organization.add(toOrganization(result)); + } + } + return organization; + } finally { + session.close(); + } + } + + @Override + public void updateOrganization(Organization organization) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateOrganization", toMap(organization)); + session.commit(); + } finally { + session.close(); + } + } + + private Organization toOrganization(final Map map) { + final Sid sid = DaoUtils.readSid(map.get("sid")); + final String domainName = DaoUtils.readString(map.get("domain_name")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final Organization.Status status = DaoUtils.readOrganizationStatus(map.get("status")); + return new Organization(sid, domainName, dateCreated, dateUpdated, status); + } + + private Map toMap(final Organization org) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(org.getSid())); + map.put("domain_name", org.getDomainName()); + map.put("date_created", DaoUtils.writeDateTime(org.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(org.getDateUpdated())); + map.put("status", DaoUtils.writeOrganizationStatus(org.getStatus())); + return map; + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisOutgoingCallerIdsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOutgoingCallerIdsDao.java similarity index 78% rename from restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisOutgoingCallerIdsDao.java rename to restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOutgoingCallerIdsDao.java index 16190d7272..18641d7af0 100644 --- a/restcomm/restcomm.dao/src/main/java/org/mobicents/servlet/restcomm/dao/mybatis/MybatisOutgoingCallerIdsDao.java +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisOutgoingCallerIdsDao.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.net.URI; import java.util.ArrayList; @@ -30,11 +30,11 @@ import org.joda.time.DateTime; -import static org.mobicents.servlet.restcomm.dao.DaoUtils.*; -import org.mobicents.servlet.restcomm.dao.OutgoingCallerIdsDao; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerId; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.OutgoingCallerIdsDao; +import org.restcomm.connect.dao.entities.OutgoingCallerId; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -126,24 +126,24 @@ public void updateOutgoingCallerId(final OutgoingCallerId outgoingCallerId) { private Map toMap(final OutgoingCallerId outgoingCallerId) { final Map map = new HashMap(); - map.put("sid", writeSid(outgoingCallerId.getSid())); - map.put("date_created", writeDateTime(outgoingCallerId.getDateCreated())); - map.put("date_updated", writeDateTime(outgoingCallerId.getDateUpdated())); + map.put("sid", DaoUtils.writeSid(outgoingCallerId.getSid())); + map.put("date_created", DaoUtils.writeDateTime(outgoingCallerId.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(outgoingCallerId.getDateUpdated())); map.put("friendly_name", outgoingCallerId.getFriendlyName()); - map.put("account_sid", writeSid(outgoingCallerId.getAccountSid())); + map.put("account_sid", DaoUtils.writeSid(outgoingCallerId.getAccountSid())); map.put("phone_number", outgoingCallerId.getPhoneNumber()); - map.put("uri", writeUri(outgoingCallerId.getUri())); + map.put("uri", DaoUtils.writeUri(outgoingCallerId.getUri())); return map; } private OutgoingCallerId toOutgoingCallerId(final Map map) { - final Sid sid = readSid(map.get("sid")); - final DateTime dateCreated = readDateTime(map.get("date_created")); - final DateTime dateUpdated = readDateTime(map.get("date_updated")); - final String friendlyName = readString(map.get("friendly_name")); - final Sid accountSid = readSid(map.get("account_sid")); - final String phoneNumber = readString(map.get("phone_number")); - final URI uri = readUri(map.get("uri")); + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final String friendlyName = DaoUtils.readString(map.get("friendly_name")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String phoneNumber = DaoUtils.readString(map.get("phone_number")); + final URI uri = DaoUtils.readUri(map.get("uri")); return new OutgoingCallerId(sid, dateCreated, dateUpdated, friendlyName, accountSid, phoneNumber, uri); } } diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfileAssociationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfileAssociationsDao.java new file mode 100644 index 0000000000..360c5f8bc0 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfileAssociationsDao.java @@ -0,0 +1,171 @@ +/* + * 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.dao.mybatis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.entities.ProfileAssociation; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisProfileAssociationsDao implements ProfileAssociationsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ProfileAssociationsDao."; + private final SqlSessionFactory sessions; + + public MybatisProfileAssociationsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public ProfileAssociation getProfileAssociationByTargetSid(String targetSid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getProfileAssociationByTargetSid", targetSid); + if (result != null) { + return toProfileAssociation(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getProfileAssociationsByProfileSid(String profileSid) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getProfileAssociationsByProfileSid", profileSid); + final List profiles = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + profiles.add(toProfileAssociation(result)); + } + } + return profiles; + } finally { + session.close(); + } + } + + @Override + public int addProfileAssociation(ProfileAssociation profileAssociation) { + final SqlSession session = sessions.openSession(); + int effectedRows = 0; + try { + effectedRows = session.insert(namespace + "addProfileAssociation", toMap(profileAssociation)); + session.commit(); + } finally { + session.close(); + } + return effectedRows; + } + + @Override + public void updateProfileAssociationOfTargetSid(ProfileAssociation profileAssociation) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateProfileAssociationOfTargetSid", toMap(profileAssociation)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateAssociatedProfileOfAllSuchProfileSid(String oldProfileSid, String newProfileSid) { + final SqlSession session = sessions.openSession(); + try { + Map map = new HashMap(); + map.put("profile_sid", newProfileSid); + map.put("old_profile_sid", oldProfileSid); + session.update(namespace + "updateAssociatedProfileOfAllSuchProfileSid", map); + session.commit(); + map = null; + } finally { + session.close(); + } + } + + @Override + public void deleteProfileAssociationByProfileSid(String profileSid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "deleteProfileAssociationByProfileSid", profileSid); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public int deleteProfileAssociationByTargetSid(String targetSid, String profileSid) { + int removed = 0; + final SqlSession session = sessions.openSession(); + final Map map = new HashMap(); + map.put("profile_sid", profileSid); + map.put("target_sid", targetSid); + try { + removed = session.delete(namespace + "deleteProfileAssociationByTargetSid", map); + session.commit(); + } finally { + session.close(); + } + return removed; + } + + private ProfileAssociation toProfileAssociation(final Map map) { + final Sid profileSid = DaoUtils.readSid(map.get("profile_sid")); + final Sid targetSid = DaoUtils.readSid(map.get("target_sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + return new ProfileAssociation(profileSid, targetSid, dateCreated.toDate(), dateUpdated.toDate()); + } + + private Map toMap(final ProfileAssociation profileAssociation) { + final Map map = new HashMap(); + map.put("profile_sid", DaoUtils.writeSid(profileAssociation.getProfileSid())); + map.put("target_sid", DaoUtils.writeSid(profileAssociation.getTargetSid())); + map.put("date_created", profileAssociation.getDateCreated()); + map.put("date_updated", profileAssociation.getDateCreated()); + return map; + } + + @Override + public int deleteProfileAssociationByTargetSid(String targetSid) { + return deleteProfileAssociationByTargetSid(targetSid, null); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfilesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfilesDao.java new file mode 100644 index 0000000000..00fe87e77e --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisProfilesDao.java @@ -0,0 +1,131 @@ +/* + * 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.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.ProfilesDao; +import org.restcomm.connect.dao.entities.Profile; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisProfilesDao implements ProfilesDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ProfilesDao."; + private final SqlSessionFactory sessions; + + public MybatisProfilesDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public Profile getProfile(String sid) throws SQLException { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getProfile", sid.toString()); + if (result != null) { + return toProfile(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getAllProfiles() throws SQLException { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getAllProfiles"); + final List profiles = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + profiles.add(toProfile(result)); + } + } + return profiles; + } finally { + session.close(); + } + } + + @Override + public int addProfile(Profile profile) { + final SqlSession session = sessions.openSession(); + int effectedRows = 0; + try { + effectedRows = session.insert(namespace + "addProfile", profile); + session.commit(); + } finally { + session.close(); + } + return effectedRows; + } + + @Override + public void updateProfile(Profile profile) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateProfile", profile); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void deleteProfile(String sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "deleteProfile", sid); + session.commit(); + } finally { + session.close(); + } + } + + + private Profile toProfile(final Map map) throws SQLException { + final String sid = DaoUtils.readString(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); +// byte[] documentArr = null; +// if (map.get("document") instanceof Blob) { +// final Blob document = (Blob) map.get("document"); +// documentArr = document.getBytes(1, (int) document.length()); +// } else { +// documentArr = (byte[]) map.get("document"); +// } + final String document = DaoUtils.readString(map.get("document")); + return new Profile(sid, document, dateCreated.toDate(), dateUpdated.toDate()); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRecordingsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRecordingsDao.java new file mode 100644 index 0000000000..5be05dabf8 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRecordingsDao.java @@ -0,0 +1,314 @@ +/* + * 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.dao.mybatis; + +import akka.dispatch.Futures; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.amazonS3.S3AccessTool; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.util.UriUtils; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.entities.MediaAttributes; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.RecordingFilter; +import scala.concurrent.ExecutionContext; +import scala.concurrent.Future; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@ThreadSafe +public final class MybatisRecordingsDao implements RecordingsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.RecordingsDao."; + private final SqlSessionFactory sessions; + private S3AccessTool s3AccessTool; + private String recordingPath; + private ExecutionContext ec; + + public MybatisRecordingsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + public MybatisRecordingsDao(final SqlSessionFactory sessions, final S3AccessTool s3AccessTool, final String recordingPath, final ExecutionContext ec) { + super(); + this.sessions = sessions; + this.s3AccessTool = s3AccessTool; + this.recordingPath = recordingPath; + this.ec = ec; + } + + @Override + public S3AccessTool getS3AccessTool () { + return s3AccessTool; + } + + @Override + public void addRecording(Recording recording, MediaAttributes.MediaType mediaType) { + final String fileExtension = mediaType.equals(MediaAttributes.MediaType.AUDIO_ONLY) ? ".wav" : ".mp4"; + if (s3AccessTool != null && ec != null) { + final String recordingSid = recording.getSid().toString(); + URI s3Uri = s3AccessTool.getS3Uri(recordingPath+"/"+recordingSid+fileExtension); + //s3AccessTool.uploadFile(recordingPath+"/"+recording.getSid().toString()+fileExtension); + if (s3Uri != null) { + recording = recording.setS3Uri(s3Uri); + } + Future f = Futures.future(new Callable() { + @Override + public Boolean call () throws Exception { + return s3AccessTool.uploadFile(recordingPath+"/"+recordingSid+fileExtension); + } + }, ec); + } + String fileUrl = String.format("/restcomm/%s/Accounts/%s/Recordings/%s",recording.getApiVersion(),recording.getAccountSid(),recording.getSid()); + recording = recording.updateFileUri(generateLocalFileUri(fileUrl, fileExtension)); + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addRecording", toMap(recording)); + session.commit(); + } finally { + session.close(); + } + } + + public URI generateLocalFileUri(String recordingRelativeUri, String fileExtension) { + URI uriToResolve = null; + try { + //For local stored recordings, add .wav/.mp4 suffix to the URI + uriToResolve = new URI(recordingRelativeUri+fileExtension); + } catch (URISyntaxException e) {} + return UriUtils.resolve(uriToResolve); + } + + @Override + public Recording getRecording(final Sid sid) { + return getRecording(namespace + "getRecording", sid); + } + + @Override + public Recording getRecordingByCall(final Sid callSid) { + return getRecording(namespace + "getRecordingByCall", callSid); + } + + @Override + public List getRecordingsByCall(Sid callSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getRecordingsByCall", callSid.toString()); + final List recordings = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + recordings.add(toRecording(result)); + } + } + return recordings; + } finally { + session.close(); + } + } + + private Recording getRecording(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(selector, sid.toString()); + if (result != null) { + return toRecording(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getRecordings(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getRecordings", accountSid.toString()); + final List recordings = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + recordings.add(toRecording(result)); + } + } + return recordings; + } finally { + session.close(); + } + } + + @Override + public List getRecordings(RecordingFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getRecordingsByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toRecording(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public Integer getTotalRecording(RecordingFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalRecordingByUsingFilters", filter); + return total; + } finally { + session.close(); + } + } + + @Override + public void removeRecording(final Sid sid) { + removeRecording(namespace + "removeRecording", sid); + } + + @Override + public void removeRecordings(final Sid accountSid) { + removeRecording(namespace + "removeRecordings", accountSid); + } + + private void removeRecording(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateRecording(final Recording recording) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateRecording", toMap(recording)); + session.commit(); + } finally { + session.close(); + } + } + + private Map toMap(final Recording recording) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(recording.getSid())); + map.put("date_created", DaoUtils.writeDateTime(recording.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(recording.getDateUpdated())); + map.put("account_sid", DaoUtils.writeSid(recording.getAccountSid())); + map.put("call_sid", DaoUtils.writeSid(recording.getCallSid())); + map.put("duration", recording.getDuration()); + map.put("api_version", recording.getApiVersion()); + map.put("uri", DaoUtils.writeUri(recording.getUri())); + map.put("file_uri", DaoUtils.writeUri(recording.getFileUri())); + if (recording.getS3Uri() != null) { + map.put("s3_uri", DaoUtils.writeUri(recording.getS3Uri())); + } else { + map.put("s3_uri", null); + } + return map; + } + + private Recording toRecording(final Map map) { + Recording recording = null; + boolean update = false; + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final Sid callSid = DaoUtils.readSid(map.get("call_sid")); + final Double duration = DaoUtils.readDouble(map.get("duration")); + final String apiVersion = DaoUtils.readString(map.get("api_version")); + final URI uri = DaoUtils.readUri(map.get("uri")); + //For backward compatibility. For old an database that we upgraded to the latest schema, the file_uri will be null so we need + //to create the file_uri on the fly + String fileUri = (String) map.get("file_uri"); + if (fileUri == null || fileUri.isEmpty()) { + String file = String.format("/restcomm/%s/Accounts/%s/Recordings/%s",apiVersion,accountSid,sid); + fileUri = generateLocalFileUri(file, ".wav").toString(); + } + + // fileUri: http://192.168.1.190:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/RE4c9c09908b60402c8c0a77e24313f27d.wav + // s3Uri: https://gvagrestcomm.s3.amazonaws.com/RE4c9c09908b60402c8c0a77e24313f27d.wav + // old S3URI: https://s3.amazonaws.com/restcomm-as-a-service/logs/RE7ddbd5b441574e4ab786a1fddf33eb47.wav?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170209T103950Z&X-Amz-SignedHeaders=host&X-Amz-Expires=604800&X-Amz-Credential=AKIAIRG5NINXKJAJM5DA%2F20170209%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=b3da2acc17ee9c6aca4cd151e154d94f530670850f0fcade2422f85d1c7cc992 + String s3Uri = (String) map.get("s3_uri"); + if (fileUri.contains("s3.amazonaws.com") && s3AccessTool != null) { + update = true; + dateUpdated = DateTime.now(); + String tempUri = fileUri; + String file = String.format("/restcomm/%s/Accounts/%s/Recordings/%s",apiVersion,accountSid,sid); + String fileExtension = null; + URI oldS3Uri = null; + try { + oldS3Uri = new URI(tempUri); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + if (oldS3Uri != null) { + String tempS3Uri = oldS3Uri.getPath().replaceFirst("/","").replaceAll("/",","); + String bucketName = tempS3Uri.split(",")[0].trim(); + String folder = tempS3Uri.split(",")[1].trim(); + String filename = tempS3Uri.split(",")[2].trim(); + fileExtension = filename.contains(".wav") ? ".wav" : ".mp4"; + StringBuffer bucket = new StringBuffer(); + bucket.append(bucketName); + if (folder != null && !folder.isEmpty()) + bucket.append("/").append(folder); + s3Uri = s3AccessTool.getS3client().getUrl(bucket.toString(), filename).toString(); + } + if (fileExtension == null) { + // assuming as WAV since previous attempt to obtain fileExtension failed + fileExtension = ".wav"; + } + fileUri = generateLocalFileUri(file, fileExtension).toString(); + } + recording = new Recording(sid, dateCreated, dateUpdated, accountSid, callSid, duration, apiVersion, uri, DaoUtils.readUri(fileUri), DaoUtils.readUri(s3Uri)); + if (update) { + updateRecording(recording); + } + return recording; + } + + +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRegistrationsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRegistrationsDao.java new file mode 100644 index 0000000000..b895960b08 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisRegistrationsDao.java @@ -0,0 +1,298 @@ +/* + * 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.dao.mybatis; + +import static org.restcomm.connect.dao.DaoUtils.readBoolean; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readInteger; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.RegistrationsDao; +import org.restcomm.connect.dao.entities.Registration; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author jean.deruelle@gmail.com (Jean Deruelle) + */ +@ThreadSafe +public final class MybatisRegistrationsDao implements RegistrationsDao { + private static final Logger logger = Logger.getLogger(MybatisRegistrationsDao.class); + + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.RegistrationsDao."; + private final SqlSessionFactory sessions; + + public MybatisRegistrationsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addRegistration(final Registration registration) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addRegistration", toMap(registration)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public List getRegistrationsByLocation(String user, String location) { + final SqlSession session = sessions.openSession(); + try { + final Map map = new HashMap(); + map.put("user_name", user); + map.put("location", location.concat("%")); + + final List> results = session.selectList(namespace + "getRegistrationsByLocation", map); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + if (!records.isEmpty()) { + Collections.sort(records); + } + } + return records; + } finally { + session.close(); + } + } + + @Override + public Registration getRegistration(String user, Sid organizationSid) { + final SqlSession session = sessions.openSession(); + try { + // https://bitbucket.org/telestax/telscale-restcomm/issue/107/dial-fails-to-call-a-client-registered + // we get all registrations and sort them by latest updated date so that we target the device where the user last + // updated the registration + final Map map = new HashMap(); + map.put("user_name", user); + map.put("organization_sid", writeSid(organizationSid)); + final List> results = session.selectList(namespace + "getRegistration", map); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + if (records.isEmpty()) { + return null; + } else { + Collections.sort(records); + return records.get(0); + } + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public Registration getRegistrationByInstanceId(String user, String instanceId) { + final SqlSession session = sessions.openSession(); + try { + // https://bitbucket.org/telestax/telscale-restcomm/issue/107/dial-fails-to-call-a-client-registered + // we get all registrations and sort them by latest updated date so that we target the device where the user last + // updated the registration + + final Map map = new HashMap(); + map.put("user_name", user); + map.put("instanceid", instanceId); + final List> results = session.selectList(namespace + "getRegistrationByInstanceId", map); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + if (records.isEmpty()) { + return null; + } else { + Collections.sort(records); + return records.get(0); + } + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getRegistrationsByInstanceId(String instanceId) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getRegistrationsByInstanceId", instanceId); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + if (!records.isEmpty()) { + Collections.sort(records); + } + } + return records; + } finally { + session.close(); + } + } + + @Override + public List getRegistrations(String user, Sid organizationSid) { + final SqlSession session = sessions.openSession(); + try { + // https://bitbucket.org/telestax/telscale-restcomm/issue/107/dial-fails-to-call-a-client-registered + // we get all registrations and sort them by latest updated date so that we target the device where the user last + // updated the registration + final Map map = new HashMap(); + map.put("user_name", user); + map.put("organization_sid", writeSid(organizationSid)); + final List> results = session.selectList(namespace + "getRegistration", map); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + if (records.isEmpty()) { + return null; + } else { + Collections.sort(records); + return records; + } + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getRegistrations() { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getRegistrations"); + final List records = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + records.add(toPresenceRecord(result)); + } + } + return records; + } finally { + session.close(); + } + } + + @Override + public boolean hasRegistration(final Registration registration) { + final SqlSession session = sessions.openSession(); + try { + final Integer result = (Integer) session.selectOne(namespace + "hasRegistration", toMap(registration)); + return result != null && result > 0; + } finally { + session.close(); + } + } + + @Override + public void removeRegistration(final Registration registration) { + final SqlSession session = sessions.openSession(); + try { + session.delete(namespace + "removeRegistration", toMap(registration)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateRegistration(final Registration registration) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateRegistration", toMap(registration)); + session.commit(); + } finally { + session.close(); + } + } + + private Map toMap(final Registration registration) { + final Map map = new HashMap(); + map.put("sid", writeSid(registration.getSid())); + map.put("instanceid", registration.getInstanceId()); + map.put("date_created", writeDateTime(registration.getDateCreated())); + map.put("date_updated", writeDateTime(registration.getDateUpdated())); + map.put("date_expires", writeDateTime(registration.getDateExpires())); + map.put("address_of_record", registration.getAddressOfRecord()); + map.put("display_name", registration.getDisplayName()); + map.put("user_name", registration.getUserName()); + map.put("location", registration.getLocation()); + map.put("user_agent", registration.getUserAgent()); + map.put("ttl", registration.getTimeToLive()); + map.put("webrtc", registration.isWebRTC()); + map.put("isLBPresent", registration.isLBPresent()); + map.put("organization_sid", DaoUtils.writeSid(registration.getOrganizationSid())); + return map; + } + + private Registration toPresenceRecord(final Map map) { + final Sid sid = readSid(map.get("sid")); + final String instanceId = readString(map.get("instanceid")); + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + final DateTime dateExpires = readDateTime(map.get("date_expires")); + final String addressOfRecord = readString(map.get("address_of_record")); + final String dislplayName = readString(map.get("display_name")); + final String userName = readString(map.get("user_name")); + final String location = readString(map.get("location")); + final String userAgent = readString(map.get("user_agent")); + final Integer timeToLive = readInteger(map.get("ttl")); + final Boolean webRTC = readBoolean(map.get("webrtc")); + Boolean isLBPresent = false; + if (readBoolean(map.get("isLBPresent")) != null) { + isLBPresent = readBoolean(map.get("isLBPresent")); + } + final Sid organizationSid = readSid(map.get("organization_sid")); + return new Registration(sid, instanceId, dateCreated, dateUpdated, dateExpires, addressOfRecord, dislplayName, userName, userAgent, + timeToLive, location, webRTC, isLBPresent, organizationSid); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisShortCodesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisShortCodesDao.java new file mode 100644 index 0000000000..e56ab16902 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisShortCodesDao.java @@ -0,0 +1,159 @@ +/* + * 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.dao.mybatis; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; + +import org.joda.time.DateTime; + +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.ShortCodesDao; +import org.restcomm.connect.dao.entities.ShortCode; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class MybatisShortCodesDao implements ShortCodesDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.ShortCodesDao."; + private final SqlSessionFactory sessions; + + public MybatisShortCodesDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addShortCode(final ShortCode shortCode) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addShortCode", toMap(shortCode)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public ShortCode getShortCode(final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getShortCode", sid.toString()); + if (result != null) { + return toShortCode(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getShortCodes(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getShortCodes", accountSid.toString()); + final List shortCodes = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + shortCodes.add(toShortCode(result)); + } + } + return shortCodes; + } finally { + session.close(); + } + } + + @Override + public void removeShortCode(final Sid sid) { + removeShortCodes(namespace + "removeShortCode", sid); + } + + @Override + public void removeShortCodes(final Sid accountSid) { + removeShortCodes(namespace + "removeShortCodes", accountSid); + } + + private void removeShortCodes(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateShortCode(final ShortCode shortCode) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateShortCode", toMap(shortCode)); + session.commit(); + } finally { + session.close(); + } + } + + private Map toMap(final ShortCode shortCode) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(shortCode.getSid())); + map.put("date_created", DaoUtils.writeDateTime(shortCode.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(shortCode.getDateUpdated())); + map.put("friendly_name", shortCode.getFriendlyName()); + map.put("account_sid", DaoUtils.writeSid(shortCode.getAccountSid())); + map.put("short_code", shortCode.getShortCode()); + map.put("api_version", shortCode.getApiVersion()); + map.put("sms_url", DaoUtils.writeUri(shortCode.getSmsUrl())); + map.put("sms_method", shortCode.getSmsMethod()); + map.put("sms_fallback_url", DaoUtils.writeUri(shortCode.getSmsFallbackUrl())); + map.put("sms_fallback_method", shortCode.getSmsFallbackMethod()); + map.put("uri", DaoUtils.writeUri(shortCode.getUri())); + return map; + } + + private ShortCode toShortCode(final Map map) { + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final String friendlyName = DaoUtils.readString(map.get("friendly_name")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final Integer shortCode = DaoUtils.readInteger(map.get("short_code")); + final String apiVersion = DaoUtils.readString(map.get("api_version")); + final URI smsUrl = DaoUtils.readUri(map.get("sms_url")); + final String smsMethod = DaoUtils.readString(map.get("sms_method")); + final URI smsFallbackUrl = DaoUtils.readUri(map.get("sms_fallback_url")); + final String smsFallbackMethod = DaoUtils.readString(map.get("sms_fallback_method")); + final URI uri = DaoUtils.readUri(map.get("uri")); + return new ShortCode(sid, dateCreated, dateUpdated, friendlyName, accountSid, shortCode, apiVersion, smsUrl, smsMethod, + smsFallbackUrl, smsFallbackMethod, uri); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisSmsMessagesDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisSmsMessagesDao.java new file mode 100644 index 0000000000..b5e5dcfe76 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisSmsMessagesDao.java @@ -0,0 +1,226 @@ +/* + * 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.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessageFilter; + +import java.math.BigDecimal; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Currency; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.restcomm.connect.dao.DaoUtils.readBigDecimal; +import static org.restcomm.connect.dao.DaoUtils.readCurrency; +import static org.restcomm.connect.dao.DaoUtils.readDateTime; +import static org.restcomm.connect.dao.DaoUtils.readSid; +import static org.restcomm.connect.dao.DaoUtils.readString; +import static org.restcomm.connect.dao.DaoUtils.readUri; +import static org.restcomm.connect.dao.DaoUtils.writeBigDecimal; +import static org.restcomm.connect.dao.DaoUtils.writeCurrency; +import static org.restcomm.connect.dao.DaoUtils.writeDateTime; +import static org.restcomm.connect.dao.DaoUtils.writeSid; +import static org.restcomm.connect.dao.DaoUtils.writeUri; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class MybatisSmsMessagesDao implements SmsMessagesDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.SmsMessagesDao."; + private final SqlSessionFactory sessions; + + public MybatisSmsMessagesDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addSmsMessage(final SmsMessage smsMessage) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addSmsMessage", toMap(smsMessage)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public SmsMessage getSmsMessage(final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(namespace + "getSmsMessage", sid.toString()); + if (result != null) { + return toSmsMessage(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getSmsMessages(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session.selectList(namespace + "getSmsMessages", accountSid.toString()); + final List smsMessages = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + smsMessages.add(toSmsMessage(result)); + } + } + return smsMessages; + } finally { + session.close(); + } + } + + @Override + public List getSmsMessages(SmsMessageFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getSmsMessagesByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toSmsMessage(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public Integer getTotalSmsMessage(SmsMessageFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalSmsMessageByUsingFilters", filter); + return total; + } finally { + session.close(); + } + } + + @Override + public void removeSmsMessage(final Sid sid) { + deleteSmsMessage(namespace + "removeSmsMessage", sid); + } + + @Override + public void removeSmsMessages(final Sid accountSid) { + deleteSmsMessage(namespace + "removeSmsMessages", accountSid); + } + + private void deleteSmsMessage(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + public void updateSmsMessage(final SmsMessage smsMessage) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateSmsMessage", toMap(smsMessage)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public int getSmsMessagesPerAccountLastPerMinute(String accountSid) throws ParseException { + SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = formatter.format(DateTime.now().minusSeconds(60).toDate()); + + Map params = new HashMap(); + params.put("start_time", date); + params.put("account_sid", accountSid); + + final SqlSession session = sessions.openSession(); + try { + final int total = session.selectOne(namespace + "getSmsMessagesPerAccountLastPerMinute", params); + return total; + } finally { + session.close(); + } + } + + private Map toMap(final SmsMessage smsMessage) { + final Map map = new HashMap(); + map.put("sid", writeSid(smsMessage.getSid())); + map.put("date_created", writeDateTime(smsMessage.getDateCreated())); + map.put("date_updated", writeDateTime(smsMessage.getDateUpdated())); + map.put("date_sent", writeDateTime(smsMessage.getDateSent())); + map.put("account_sid", writeSid(smsMessage.getAccountSid())); + map.put("sender", smsMessage.getSender()); + map.put("recipient", smsMessage.getRecipient()); + map.put("body", smsMessage.getBody()); + map.put("status", smsMessage.getStatus().toString()); + map.put("direction", smsMessage.getDirection().toString()); + map.put("price", writeBigDecimal(smsMessage.getPrice())); + map.put("price_unit", writeCurrency(smsMessage.getPriceUnit())); + map.put("api_version", smsMessage.getApiVersion()); + map.put("uri", writeUri(smsMessage.getUri())); + return map; + } + + private SmsMessage toSmsMessage(final Map map) { + final Sid sid = readSid(map.get("sid")); + final DateTime dateCreated = readDateTime(map.get("date_created")); + final DateTime dateUpdated = readDateTime(map.get("date_updated")); + final DateTime dateSent = readDateTime(map.get("date_sent")); + final Sid accountSid = readSid(map.get("account_sid")); + final String sender = readString(map.get("sender")); + final String recipient = readString(map.get("recipient")); + final String body = readString(map.get("body")); + final SmsMessage.Status status = SmsMessage.Status.getStatusValue(readString(map.get("status"))); + final SmsMessage.Direction direction = SmsMessage.Direction.getDirectionValue(readString(map.get("direction"))); + final BigDecimal price = readBigDecimal(map.get("price")); + final Currency priceUnit = readCurrency(map.get("price_unit")); + final String apiVersion = readString(map.get("api_version")); + final URI uri = readUri(map.get("uri")); + return new SmsMessage(sid, dateCreated, dateUpdated, dateSent, accountSid, sender, recipient, body, status, direction, + price, priceUnit, apiVersion, uri); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisTranscriptionsDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisTranscriptionsDao.java new file mode 100644 index 0000000000..315d55d3bf --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisTranscriptionsDao.java @@ -0,0 +1,203 @@ +/* + * 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.dao.mybatis; + +import java.math.BigDecimal; +import java.net.URI; +import java.util.ArrayList; +import java.util.Currency; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; + +import org.joda.time.DateTime; + +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.TranscriptionsDao; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Transcription; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.TranscriptionFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class MybatisTranscriptionsDao implements TranscriptionsDao { + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.TranscriptionsDao."; + private final SqlSessionFactory sessions; + + public MybatisTranscriptionsDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public void addTranscription(final Transcription transcription) { + final SqlSession session = sessions.openSession(); + try { + session.insert(namespace + "addTranscription", toMap(transcription)); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public Transcription getTranscription(final Sid sid) { + return getTranscription(namespace + "getTranscription", sid); + } + + @Override + public Transcription getTranscriptionByRecording(final Sid recordingSid) { + return getTranscription(namespace + "getTranscriptionByRecording", recordingSid); + } + + private Transcription getTranscription(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + final Map result = session.selectOne(selector, sid.toString()); + if (result != null) { + return toTranscription(result); + } else { + return null; + } + } finally { + session.close(); + } + } + + @Override + public List getTranscriptions(final Sid accountSid) { + final SqlSession session = sessions.openSession(); + try { + final List> results = session + .selectList(namespace + "getTranscriptions", accountSid.toString()); + final List transcriptions = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + transcriptions.add(toTranscription(result)); + } + } + return transcriptions; + } finally { + session.close(); + } + } + + @Override + public List getTranscriptions(TranscriptionFilter filter) { + + final SqlSession session = sessions.openSession(); + + try { + final List> results = session.selectList(namespace + "getTranscriptionsByUsingFilters", + filter); + final List cdrs = new ArrayList(); + + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + cdrs.add(toTranscription(result)); + } + } + return cdrs; + } finally { + session.close(); + } + } + + @Override + public Integer getTotalTranscription(TranscriptionFilter filter) { + final SqlSession session = sessions.openSession(); + try { + final Integer total = session.selectOne(namespace + "getTotalTranscriptionByUsingFilters", filter); + return total; + } finally { + session.close(); + } + } + + @Override + public void removeTranscription(final Sid sid) { + removeTranscriptions(namespace + "removeTranscription", sid); + } + + @Override + public void removeTranscriptions(final Sid accountSid) { + removeTranscriptions(namespace + "removeTranscriptions", accountSid); + } + + private void removeTranscriptions(final String selector, final Sid sid) { + final SqlSession session = sessions.openSession(); + try { + session.delete(selector, sid.toString()); + session.commit(); + } finally { + session.close(); + } + } + + @Override + public void updateTranscription(final Transcription transcription) { + final SqlSession session = sessions.openSession(); + try { + session.update(namespace + "updateTranscription", toMap(transcription)); + session.commit(); + } finally { + session.close(); + } + } + + private Map toMap(final Transcription transcription) { + final Map map = new HashMap(); + map.put("sid", DaoUtils.writeSid(transcription.getSid())); + map.put("date_created", DaoUtils.writeDateTime(transcription.getDateCreated())); + map.put("date_updated", DaoUtils.writeDateTime(transcription.getDateUpdated())); + map.put("account_sid", DaoUtils.writeSid(transcription.getAccountSid())); + map.put("status", transcription.getStatus().toString()); + map.put("recording_sid", DaoUtils.writeSid(transcription.getRecordingSid())); + map.put("duration", transcription.getDuration()); + map.put("transcription_text", transcription.getTranscriptionText()); + map.put("price", DaoUtils.writeBigDecimal(transcription.getPrice())); + map.put("price_unit", DaoUtils.writeCurrency(transcription.getPriceUnit())); + map.put("uri", DaoUtils.writeUri(transcription.getUri())); + return map; + } + + private Transcription toTranscription(final Map map) { + final Sid sid = DaoUtils.readSid(map.get("sid")); + final DateTime dateCreated = DaoUtils.readDateTime(map.get("date_created")); + final DateTime dateUpdated = DaoUtils.readDateTime(map.get("date_updated")); + final Sid accountSid = DaoUtils.readSid(map.get("account_sid")); + final String text = DaoUtils.readString(map.get("status")); + final Transcription.Status status = Transcription.Status.getStatusValue(text); + final Sid recordingSid = DaoUtils.readSid(map.get("recording_sid")); + final Double duration = DaoUtils.readDouble(map.get("duration")); + final String transcriptionText = DaoUtils.readString(map.get("transcription_text")); + final BigDecimal price = DaoUtils.readBigDecimal(map.get("price")); + final Currency priceUnit = DaoUtils.readCurrency(map.get("price_unit")); + final URI uri = DaoUtils.readUri(map.get("uri")); + return new Transcription(sid, dateCreated, dateUpdated, accountSid, status, recordingSid, duration, transcriptionText, + price, priceUnit, uri); + } +} diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisUsageDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisUsageDao.java new file mode 100644 index 0000000000..0d81dd73c5 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisUsageDao.java @@ -0,0 +1,227 @@ +/* + * 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.dao.mybatis; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.restcomm.connect.dao.DaoUtils; +import org.restcomm.connect.dao.UsageDao; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Usage; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import java.math.BigDecimal; +import java.net.URI; +import java.sql.Date; +import java.util.Currency; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@ThreadSafe +public final class MybatisUsageDao implements UsageDao { + + private static final String namespace = "org.mobicents.servlet.sip.restcomm.dao.UsageDao."; + private final SqlSessionFactory sessions; + + public MybatisUsageDao(final SqlSessionFactory sessions) { + super(); + this.sessions = sessions; + } + + @Override + public List getUsage(final Sid accountSid, String uri) { + return getUsageCalls(accountSid, null, null, null, uri, "getAllTimeCalls"); + } + + @Override + public List getUsageDaily(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri) { + return getUsageCalls(accountSid, category, startDate, endDate, uri, "getDailyCalls"); + } + + @Override + public List getUsageMonthly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri) { + return getUsageCalls(accountSid, category, startDate, endDate, uri, "getMonthlyCalls"); + } + + @Override + public List getUsageYearly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri) { + return getUsageCalls(accountSid, category, startDate, endDate, uri, "getYearlyCalls"); + } + + @Override + public List getUsageAllTime(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri) { + return getUsageCalls(accountSid, category, startDate, endDate, uri, "getAllTimeCalls"); + } + + @Override + public List getUsage(final Sid accountSid) { + return getUsage(accountSid, ""); + } + + @Override + public List getUsageDaily(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageDaily(accountSid, category, startDate, endDate, ""); + } + + @Override + public List getUsageMonthly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageMonthly(accountSid, category, startDate, endDate, ""); + } + + @Override + public List getUsageYearly(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageYearly(accountSid, category, startDate, endDate, ""); + } + + @Override + public List getUsageAllTime(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageAllTime(accountSid, category, startDate, endDate, ""); + } + /* + @Override + public List getUsageToday(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageCalls(accountSid, category, startDate, endDate, "getTodayCalls"); + } + + @Override + public List getUsageYesterday(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageCalls(accountSid, category, startDate, endDate, "getYesterdayCalls"); + } + + @Override + public List getUsageThisMonth(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageCalls(accountSid, category, startDate, endDate, "getThisMonthCalls"); + } + + @Override + public List getUsageLastMonth(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate) { + return getUsageCalls(accountSid, category, startDate, endDate, "getLastMonthCalls"); + } + */ + private List getUsageCalls(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, final String queryName) { + return getUsageCalls(accountSid, category, startDate, endDate, "", queryName); + } + private List getUsageCalls(final Sid accountSid, Usage.Category category, DateTime startDate, DateTime endDate, String uri, final String queryName) { + long startTime = System.currentTimeMillis(); + final SqlSession session = sessions.openSession(); + Map params = new HashMap(); + params.put("sid", accountSid.toString()); + params.put("startDate", new Date(startDate.getMillis())); + params.put("endDate", new Date(endDate.getMillis())); + params.put("uri", uri); + fillParametersByCategory(category, params); + try { + final List> results = session.selectList(namespace + queryName, params); + final List usageRecords = new ArrayList(); + if (results != null && !results.isEmpty()) { + for (final Map result : results) { + usageRecords.add(toUsageRecord(accountSid, result)); + } + } + return usageRecords; + } finally { + session.close(); + } + } + + private Usage toUsageRecord(final Sid accountSid, final Map map) { + final Usage.Category category = Usage.Category.CALLS; + final String description = "Total Calls"; + final DateTime startDate = DateTimeFormat.forPattern("yyyyy-MM-dd").parseDateTime(map.get("start_date").toString()); + final DateTime endDate = DateTimeFormat.forPattern("yyyyy-MM-dd").parseDateTime(map.get("end_date").toString()); + + final Long usage = DaoUtils.readLong(map.get("usage")); + final String usageUnit = "minutes"; + + final Long count = DaoUtils.readLong(map.get("count")); + final String countUnit = "calls"; + + /* FIXME: readBigDecimal should take Double instead of String ? */ + final BigDecimal price = DaoUtils.readBigDecimal(map.get("price").toString()); + final Currency priceUnit = Currency.getInstance(Locale.US); + + final URI uri = DaoUtils.readUri(map.get("uri")); + + return new Usage(category, description, accountSid, startDate, endDate, usage, usageUnit, count, countUnit, price, priceUnit, uri); + } + + private Map fillParametersByCategory(Usage.Category category, Map params) { + // FIXME: handle no category, meaning all + if (category == null) category = Usage.Category.CALLS; + + params.put("category", category.toString()); + switch (category) { + case CALLS: + case CALLS_INBOUND: + case CALLS_INBOUND_LOCAL: + case CALLS_INBOUND_TOLLFREE: + case CALLS_OUTBOUND: + case CALLS_CLIENT: + case CALLS_SIP: + params.put("tableName", "restcomm_call_detail_records"); + //NB: #1690 display duration as minutes rounded up + params.put("usageExprPre", "COALESCE( CEIL(SUM("); + params.put("usageExprCol", "duration"); + params.put("usageExprSuf", ") /60),0) "); + break; + case SMS: + case SMS_INBOUND: + case SMS_INBOUND_SHORTCODE: + case SMS_INBOUND_LONGCODE: + case SMS_OUTBOUND: + case SMS_OUTBOUND_SHORTCODE: + case SMS_OUTBOUND_LONGCODE: + params.put("tableName", "restcomm_sms_messages"); + params.put("usageExprPre", "COUNT("); + params.put("usageExprCol", "sid"); + params.put("usageExprSuf", ")"); + break; + case PHONENUMBERS: + case PHONENUMBERS_TOLLFREE: + case PHONENUMBERS_LOCAL: + case SHORTCODES: + case SHORTCODES_VANITY: + case SHORTCODES_RANDOM: + case SHORTCODES_CUSTOMEROWNED: + case CALLERIDLOOKUPS: + case RECORDINGS: + case TRANSCRIPTIONS: + case RECORDINGSTORAGE: + case TOTALPRICE: + default: + params.put("tableName", "restcomm_call_detail_records"); + //NB: #1690 display duration as minutes rounded up + params.put("usageExprPre", "COALESCE( CEIL(SUM("); + params.put("usageExprCol", "duration"); + params.put("usageExprSuf", ") /60),0)"); + break; + } + return params; + } + +} diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/accounts.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/accounts.xml new file mode 100644 index 0000000000..9000c7fd4a --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/accounts.xml @@ -0,0 +1,47 @@ + + + + + + INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "parent_sid", "type", "status", "auth_token", "role", "uri", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{parent_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}, #{organization_sid}); + + + + + + + + + + + + + + DELETE FROM "restcomm_accounts" WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_accounts" SET "date_updated"=#{date_updated}, "email_address"=#{email_address}, "friendly_name"=#{friendly_name}, + "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role} WHERE "sid"=#{sid}; + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/announcements.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/announcements.xml similarity index 87% rename from restcomm/restcomm.dao/src/test/resources/announcements.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/announcements.xml index 62a5a7bae9..1e4c8c014a 100644 --- a/restcomm/restcomm.dao/src/test/resources/announcements.xml +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/announcements.xml @@ -20,4 +20,8 @@ DELETE FROM "restcomm_announcements" WHERE "sid"=#{sid}; + + + DELETE FROM "restcomm_announcements" WHERE "account_sid"=#{account_sid}; + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/applications.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/applications.xml new file mode 100644 index 0000000000..81206d8acc --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/applications.xml @@ -0,0 +1,82 @@ + + + + + + + + INSERT INTO "restcomm_applications" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "api_version", + "voice_caller_id_lookup", "uri", "rcml_url", "kind") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{api_version}, + #{voice_caller_id_lookup}, #{uri}, #{rcml_url}, #{kind}); + + + + + + + + + + + + + DELETE FROM "restcomm_applications" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_applications" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_applications" SET "friendly_name"=#{friendly_name}, "date_updated"=#{date_updated}, + "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "rcml_url"=#{rcml_url}, "kind"=#{kind} + WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/available-phone-numbers.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/available-phone-numbers.xml similarity index 89% rename from restcomm/restcomm.dao/src/test/resources/available-phone-numbers.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/available-phone-numbers.xml index e157099c71..1694a57aa7 100644 --- a/restcomm/restcomm.dao/src/test/resources/available-phone-numbers.xml +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/available-phone-numbers.xml @@ -5,8 +5,8 @@ --> - INSERT INTO "restcomm_available_phone_numbers" ("friendly_name", "phone_number", "lata", "rate_center", "latitude", "longitude", "region", "postal_code", "iso_country") - VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}); + INSERT INTO "restcomm_available_phone_numbers" ("friendly_name", "phone_number", "lata", "rate_center", "latitude", "longitude", "region", "postal_code", "iso_country", "voice_capable", "sms_capable", "mms_capable", "fax_capable", "cost") + VALUES (#{friendly_name}, #{phone_number}, #{lata}, #{rate_center}, #{latitude}, #{longitude}, #{region}, #{postal_code}, #{iso_country}, #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{cost}); + SELECT * FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_call_detail_records" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_call_detail_records" + SET "date_updated"=#{date_updated}, "status"=#{status}, "start_time"=#{start_time}, "end_time"=#{end_time}, "duration"=#{duration}, + "price"=#{price}, "answered_by"=#{answered_by}, "forwarded_from"=#{forwarded_from}, "ring_duration"=#{ring_duration}, "conference_sid"=#{conference_sid}, "muted"=#{muted}, "start_conference_on_enter"=#{start_conference_on_enter}, + "end_conference_on_exit"=#{end_conference_on_exit}, "on_hold"=#{on_hold}, "ms_id"=#{ms_id} + WHERE "sid"=#{sid}; + + + UPDATE "restcomm_call_detail_records" + SET "status"='completed' + WHERE "instanceid"=#{instanceid} AND (UPPER("status") = ('IN_PROGRESS') OR + UPPER("status") = ('IN-PROGRESS') OR UPPER("status") = ('RINGING') OR UPPER("status") = ('QUEUED')); + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/clients.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/clients.xml new file mode 100644 index 0000000000..cb4fff1d83 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/clients.xml @@ -0,0 +1,43 @@ + + + + + + INSERT INTO "restcomm_clients" ("sid", "date_created", "date_updated", "account_sid", "api_version", "friendly_name", "login", "password", + "status", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "voice_application_sid", "uri", "push_client_identity") VALUES (#{sid}, + #{date_created}, #{date_updated}, #{account_sid}, #{api_version}, #{friendly_name}, #{login}, #{password}, #{status}, #{voice_url}, + #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}, #{push_client_identity}); + + + + + + + + + + + + DELETE FROM "restcomm_clients" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_clients" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_clients" SET "friendly_name"=#{friendly_name}, "password"=#{password}, "status"=#{status}, "voice_url"=#{voice_url}, + "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, + "voice_application_sid"=#{voice_application_sid}, "push_client_identity"=#{push_client_identity} WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/conference-detail-records.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/conference-detail-records.xml new file mode 100644 index 0000000000..6dd8206d91 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/conference-detail-records.xml @@ -0,0 +1,134 @@ + + + + + + + INSERT INTO "restcomm_conference_detail_records" ("sid", "date_created", "date_updated", "account_sid", "status", "friendly_name", "api_version", "uri", "master_ms_id", "master_present") VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{friendly_name}, #{api_version}, #{uri}, #{master_ms_id}, #{master_present}); + + + + + + + + + + + + + DELETE FROM "restcomm_conference_detail_records" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_conference_detail_records" WHERE "account_sid"=#{account_sid}; + + + + UPDATE + "restcomm_conference_detail_records" + SET "status"=#{status}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET + "master_conference_endpoint_id"=#{master_conference_endpoint_id}, + "master_ivr_endpoint_id"=#{master_ivr_endpoint_id}, + "master_ivr_endpoint_session_id"=#{master_ivr_endpoint_session_id}, + "master_ivr_conn_id"=#{master_ivr_conn_id}, + "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET + "master_bridge_endpoint_id"=#{master_bridge_endpoint_id}, + "master_bridge_endpoint_session_id"=#{master_bridge_endpoint_session_id}, + "master_bridge_conn_id"=#{master_bridge_conn_id}, + "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET "master_present"=#{master_present}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + UPDATE + "restcomm_conference_detail_records" + SET "moderator_present"=#{moderator_present}, "date_updated"=#{date_updated} + WHERE "sid"=#{sid}; + + + diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/extensions-configuration.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/extensions-configuration.xml new file mode 100644 index 0000000000..b20ac5233b --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/extensions-configuration.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + INSERT INTO "restcomm_extensions_configuration" ("sid", "extension", "configuration_data", "configuration_type", + "date_created", "date_updated", "enabled") VALUES (#{sid}, #{extension}, #{configuration_data}, #{configuration_type}, + #{date_created}, #{date_updated}, #{enabled}); + + + + UPDATE "restcomm_extensions_configuration" SET "configuration_data"=#{configuration_data}, "configuration_type"=#{configuration_type}, "date_updated"=#{date_updated}, "enabled"=#{enabled} + WHERE "sid"=#{sid} + + + + + + + + + + DELETE FROM "restcomm_extensions_configuration" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_extensions_configuration" WHERE "extension"=#{extension}; + + + + + + + + + + INSERT INTO "restcomm_accounts_extensions" ("account_sid", "extension_sid", "configuration_data") + VALUES (#{account_sid}, #{extension_sid}, #{configuration_data}); + + + + UPDATE "restcomm_accounts_extensions" SET "configuration_data"=#{configuration_data} + WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid}; + + + + DELETE FROM "restcomm_accounts_extensions" + WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid}; + + diff --git a/restcomm/restcomm.dao/src/test/resources/gateways.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/gateways.xml similarity index 100% rename from restcomm/restcomm.dao/src/test/resources/gateways.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/gateways.xml diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/geolocation.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/geolocation.xml new file mode 100644 index 0000000000..1b46e5dd2f --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/geolocation.xml @@ -0,0 +1,40 @@ + + + + + + INSERT INTO "restcomm_geolocation"("sid", "date_created", "date_updated", "date_executed", "account_sid", "source", "device_identifier", + "geolocation_type", "response_status", "cell_id", "location_area_code", "mobile_country_code", "mobile_network_code", + "network_entity_address", "age_of_location_info", "device_latitude", "device_longitude", "accuracy", "physical_address", "internet_address", + "formatted_address", "location_timestamp", "event_geofence_latitude", "event_geofence_longitude", "radius", "geolocation_positioning_type", + "last_geolocation_response", "cause", "api_version", "uri") VALUES(#{sid}, #{date_created}, #{date_updated}, #{date_executed}, #{account_sid}, + #{source}, #{device_identifier}, #{geolocation_type}, #{response_status}, #{cell_id}, #{location_area_code}, + #{mobile_country_code}, #{mobile_network_code}, #{network_entity_address}, #{age_of_location_info}, #{device_latitude}, #{device_longitude}, + #{accuracy}, #{physical_address}, #{internet_address}, #{formatted_address}, #{location_timestamp}, #{event_geofence_latitude}, + #{event_geofence_longitude}, #{radius}, #{geolocation_positioning_type}, #{last_geolocation_response}, #{cause}, #{api_version}, + #{uri}); + + + + + + + + DELETE FROM "restcomm_geolocation" WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_geolocation" SET "date_updated"=#{date_updated}, "source"=#{source}, "response_status"=#{response_status}, + "cell_id"=#{cell_id}, "location_area_code"=#{location_area_code}, "mobile_country_code"=#{mobile_country_code}, + "mobile_network_code"=#{mobile_network_code}, "network_entity_address"=#{network_entity_address}, "age_of_location_info"=#{age_of_location_info}, + "device_latitude"=#{device_latitude}, "device_longitude"=#{device_longitude}, "accuracy"=#{accuracy}, "physical_address"=#{physical_address}, + "internet_address"=#{internet_address}, "formatted_address"=#{formatted_address}, "location_timestamp"=#{location_timestamp}, + "event_geofence_latitude"=#{event_geofence_latitude}, "event_geofence_longitude"=#{event_geofence_longitude}, + "radius"=#{radius}, "geolocation_positioning_type"=#{geolocation_positioning_type}, "last_geolocation_response"=#{last_geolocation_response}, + "cause"=#{cause} WHERE "sid"=#{sid}; + + diff --git a/restcomm/restcomm.dao/src/test/resources/http-cookies.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/http-cookies.xml similarity index 100% rename from restcomm/restcomm.dao/src/test/resources/http-cookies.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/http-cookies.xml diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/incoming-phone-numbers.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/incoming-phone-numbers.xml new file mode 100644 index 0000000000..7a73478b67 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/incoming-phone-numbers.xml @@ -0,0 +1,202 @@ + + + + + + INSERT INTO "restcomm_incoming_phone_numbers" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "phone_number", "api_version", + "voice_caller_id_lookup", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", + "voice_application_sid", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_application_sid", "uri", "voice_capable", "sms_capable", + "mms_capable", "fax_capable", "pure_sip", "cost", "ussd_url", "ussd_method", "ussd_fallback_url", "ussd_fallback_method", "ussd_application_sid", "refer_url", "refer_method", "refer_application_sid", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, + #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, + #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}, + #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{pure_sip}, #{cost}, #{ussd_url}, #{ussd_method}, #{ussd_fallback_url}, + #{ussd_fallback_method}, #{ussd_application_sid}, #{refer_url}, #{refer_method}, #{refer_application_sid}, #{organization_sid}); + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_incoming_phone_numbers" SET "friendly_name"=#{friendly_name}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "voice_url"=#{voice_url}, + "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, + "status_callback_method"=#{status_callback_method}, "voice_application_sid"=#{voice_application_sid}, "sms_url"=#{sms_url}, "sms_method"=#{sms_method}, + "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, "sms_application_sid"=#{sms_application_sid}, + "voice_capable"=#{voice_capable}, + "sms_capable"=#{sms_capable}, "mms_capable"=#{mms_capable}, "fax_capable"=#{fax_capable}, "ussd_url"=#{ussd_url}, "ussd_method"=#{ussd_method}, + "ussd_fallback_url"=#{ussd_fallback_url}, "ussd_fallback_method"=#{ussd_fallback_method}, "ussd_application_sid"=#{ussd_application_sid}, + "refer_url"=#{refer_url}, "refer_method"=#{refer_method}, "refer_application_sid"=#{refer_application_sid}, "organization_sid"=#{organization_sid} WHERE "sid"=#{sid}; + + diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/instanceId.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/instanceId.xml new file mode 100644 index 0000000000..87f93bd056 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/instanceId.xml @@ -0,0 +1,25 @@ + + + + + + INSERT INTO "restcomm_instance_id" ("instance_id", "host", "date_created", "date_updated") + VALUES(#{instance_id}, #{host}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE "restcomm_instance_id" SET "date_updated"=#{date_updated}, "instance_id"=#{instance_id} WHERE "instance_id"=#{instance_id}; + + + + DELETE FROM "restcomm_instance_id" WHERE "instance_id"=#{instance_id}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-resource-broker-entity.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-resource-broker-entity.xml new file mode 100644 index 0000000000..7ea6a90668 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-resource-broker-entity.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO + "restcomm_media_resource_broker_entity" + ("conference_sid", "slave_ms_id", "slave_ms_bridge_ep_id", "slave_ms_cnf_ep_id", + "is_bridged_together") + VALUES + (#{conference_sid}, #{slave_ms_id}, #{slave_ms_bridge_ep_id}, #{slave_ms_cnf_ep_id}, + #{is_bridged_together}); + + + + + + + DELETE FROM "restcomm_media_resource_broker_entity" WHERE "conference_sid"=#{conferenceSid} AND "slave_ms_id"=#{slaveMsId}; + + + + UPDATE "restcomm_media_resource_broker_entity" + SET "slave_ms_bridge_ep_id"=#{slave_ms_bridge_ep_id}, + "slave_ms_cnf_ep_id"=#{slave_ms_cnf_ep_id}, "is_bridged_together"=#{is_bridged_together} + WHERE "conference_sid"=#{conference_sid} AND "slave_ms_id"=#{slave_ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-servers.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-servers.xml new file mode 100644 index 0000000000..5236ca3d2a --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/media-servers.xml @@ -0,0 +1,36 @@ + + + + + + + INSERT INTO "restcomm_media_servers" ("local_ip", "local_port", "remote_ip", "remote_port", "compatibility", "response_timeout", "external_address") + VALUES (#{local_ip}, #{local_port}, #{remote_ip}, #{remote_port}, #{compatibility}, #{response_timeout}, #{external_address}); + + + + + + + + + + DELETE FROM "restcomm_media_servers" WHERE "ms_id"=#{ms_id}; + + + + UPDATE "restcomm_media_servers" + SET "local_ip"=#{local_ip}, "local_port"=#{local_port}, "remote_ip"=#{remote_ip}, "remote_port"=#{remote_port}, + "compatibility"=#{compatibility}, "response_timeout"=#{response_timeout}, "external_address"=#{external_address} + WHERE "ms_id"=#{ms_id}; + + + \ No newline at end of file diff --git a/restcomm/restcomm.rvd/src/main/webapp/protoProjects/_proto_voice/data/.forgit b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/migration.xml similarity index 100% rename from restcomm/restcomm.rvd/src/main/webapp/protoProjects/_proto_voice/data/.forgit rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/migration.xml diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/notifications.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/notifications.xml new file mode 100644 index 0000000000..3417cb17a7 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/notifications.xml @@ -0,0 +1,129 @@ + + + + + + INSERT INTO "restcomm_notifications" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "api_version", "log", "error_code", "more_info", "message_text", + "message_date", "request_url", "request_method", "request_variables", "response_headers", "response_body", "uri") VALUES (#{sid}, #{date_created}, #{date_updated}, + #{account_sid}, #{call_sid}, #{api_version}, #{log}, #{error_code}, #{more_info}, #{message_text}, #{message_date}, #{request_url}, #{request_method}, + #{request_variables}, #{response_headers}, #{response_body}, #{uri}); + + + + + + + + + + + + + + DELETE FROM "restcomm_notifications" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_notifications" WHERE "account_sid"=#{account_sid}; + + + + DELETE FROM "restcomm_notifications" WHERE "call_sid"=#{call_sid}; + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/organization.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/organization.xml new file mode 100644 index 0000000000..15d6a3a4b1 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/organization.xml @@ -0,0 +1,31 @@ + + + + + + INSERT INTO "restcomm_organizations" ("sid", "domain_name", "date_created", "date_updated", "status") + VALUES(#{sid}, #{domain_name}, #{date_created}, #{date_updated}, #{status}); + + + + + + + + + + + + UPDATE "restcomm_organizations" SET "date_updated"=#{date_updated}, + "domain_name"=#{domain_name} + WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/outgoing-caller-ids.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/outgoing-caller-ids.xml similarity index 100% rename from restcomm/restcomm.dao/src/test/resources/outgoing-caller-ids.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/outgoing-caller-ids.xml diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/profile-association.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/profile-association.xml new file mode 100644 index 0000000000..3b0adf8977 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/profile-association.xml @@ -0,0 +1,46 @@ + + + + + + INSERT INTO "restcomm_profile_associations" ("profile_sid", "target_sid", "date_created", "date_updated") + VALUES(#{profile_sid}, #{target_sid}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "target_sid"=#{target_sid}; + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "profile_sid"=#{old_profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE "profile_sid"=#{profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE '1' = '1' + + AND "target_sid" = #{target_sid} + + + AND "profile_sid" = #{profile_sid} + + ; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/recordings.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/recordings.xml new file mode 100644 index 0000000000..9357b6314d --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/recordings.xml @@ -0,0 +1,112 @@ + + + + + + INSERT INTO "restcomm_recordings" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "duration", "api_version", "uri", "file_uri", "s3_uri") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}, #{file_uri}, #{s3_uri}); + + + + UPDATE "restcomm_recordings" + SET "date_updated"=#{date_updated}, "uri"=#{uri}, "file_uri"=#{file_uri}, "s3_uri"=#{s3_uri} + WHERE "sid"=#{sid}; + + + + + + + + + + + + DELETE FROM "restcomm_recordings" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_recordings" WHERE "account_sid"=#{account_sid}; + + + + + + diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/registrations.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/registrations.xml new file mode 100644 index 0000000000..a4b70c7264 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/registrations.xml @@ -0,0 +1,47 @@ + + + + + + INSERT INTO "restcomm_registrations" ("sid", "date_created", "date_updated", "date_expires", "address_of_record", "display_name", + "user_name", "user_agent", "ttl", "location", "webrtc", "instanceid", "isLBPresent", "organization_sid") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_expires}, #{address_of_record}, #{display_name}, #{user_name}, #{user_agent}, + #{ttl}, #{location}, #{webrtc}, #{instanceid}, #{isLBPresent}, #{organization_sid}); + + + + + + + + + + + + + + + + DELETE FROM "restcomm_registrations" WHERE "location"=#{location} AND "address_of_record"=#{address_of_record}; + + + + UPDATE "restcomm_registrations" SET "ttl"=#{ttl}, "date_expires"=#{date_expires}, "date_updated"=#{date_updated}, "instanceid"=#{instanceid} WHERE "address_of_record"=#{address_of_record} AND + "display_name"=#{display_name} AND "location"=#{location} AND "user_agent"=#{user_agent}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/sand-boxes.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/sand-boxes.xml similarity index 100% rename from restcomm/restcomm.dao/src/test/resources/sand-boxes.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/sand-boxes.xml diff --git a/restcomm/restcomm.dao/src/test/resources/short-codes.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/short-codes.xml similarity index 100% rename from restcomm/restcomm.dao/src/test/resources/short-codes.xml rename to restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/short-codes.xml diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/sms-messages.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/sms-messages.xml new file mode 100644 index 0000000000..cffdc27f72 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/sms-messages.xml @@ -0,0 +1,122 @@ + + + + + + INSERT INTO "restcomm_sms_messages" ("sid", "date_created", "date_updated", "date_sent", "account_sid", "sender", "recipient", "body", "status", "direction", "price", + "api_version", "uri") VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_sent}, #{account_sid}, #{sender}, #{recipient}, #{body}, + #{status}, #{direction}, #{price}, #{api_version}, #{uri}); + + + + + + + + DELETE FROM "restcomm_sms_messages" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_sms_messages" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_sms_messages" SET "date_sent"=#{date_sent}, "status"=#{status}, "price"=#{price} WHERE "sid"=#{sid}; + + + + + + + + + diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/transcriptions.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/transcriptions.xml new file mode 100644 index 0000000000..c92c5feeb5 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/transcriptions.xml @@ -0,0 +1,110 @@ + + + + + + INSERT INTO "restcomm_transcriptions" ("sid", "date_created", "date_updated", "account_sid", "status", "recording_sid", "duration", "transcription_text", "price", "uri") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{recording_sid}, #{duration}, #{transcription_text}, #{price}, #{uri}); + + + + + + + + + + DELETE FROM "restcomm_transcriptions" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_transcriptions" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_transcriptions" SET "status"=#{status} + + , "transcription_text"=#{transcription_text} + + WHERE "sid"=#{sid}; + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/usage.xml b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/usage.xml new file mode 100644 index 0000000000..ff13d4f2d6 --- /dev/null +++ b/restcomm/restcomm.dao/src/main/resources/org/restcomm/connect/dao/mybatis/usage.xml @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/AccountsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/AccountsDaoTest.java deleted file mode 100644 index afd857d0ab..0000000000 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/AccountsDaoTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.mobicents.servlet.restcomm.dao.mybatis; - -import java.io.InputStream; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class AccountsDaoTest { - private static MybatisDaoManager manager; - - public AccountsDaoTest() { - super(); - } - - @Before - public void before() throws Exception { - final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final SqlSessionFactory factory = builder.build(data); - manager = new MybatisDaoManager(); - manager.start(factory); - } - - @After - public void after() throws Exception { - manager.shutdown(); - } - - @Test - public void createReadUpdateDelete() { - - } -} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ApplicationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ApplicationsDaoTest.java deleted file mode 100644 index 4bf2eff298..0000000000 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ApplicationsDaoTest.java +++ /dev/null @@ -1,185 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.io.InputStream; -import java.net.URI; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; - -import org.junit.After; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; - -import org.mobicents.servlet.restcomm.dao.ApplicationsDao; -import org.mobicents.servlet.restcomm.entities.Application; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class ApplicationsDaoTest { - private static MybatisDaoManager manager; - - public ApplicationsDaoTest() { - super(); - } - - @Before - public void before() { - final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final SqlSessionFactory factory = builder.build(data); - manager = new MybatisDaoManager(); - manager.start(factory); - } - - @After - public void after() { - manager.shutdown(); - } - - @Test - public void createReadUpdateDelete() { - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid sid = Sid.generate(Sid.Type.APPLICATION); - URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - String method = "GET"; - final Application.Builder builder = Application.builder(); - builder.setSid(sid); - builder.setFriendlyName("Test Application"); - builder.setAccountSid(account); - builder.setApiVersion("2012-04-24"); - builder.setHasVoiceCallerIdLookup(false); - builder.setVoiceUrl(url); - builder.setVoiceMethod(method); - builder.setVoiceFallbackUrl(url); - builder.setVoiceFallbackMethod(method); - builder.setStatusCallback(url); - builder.setStatusCallbackMethod(method); - builder.setSmsUrl(url); - builder.setSmsMethod(method); - builder.setSmsFallbackUrl(url); - builder.setSmsFallbackMethod(method); - builder.setSmsStatusCallback(url); - builder.setUri(url); - Application application = builder.build(); - final ApplicationsDao applications = manager.getApplicationsDao(); - // Create a new application in the data store. - applications.addApplication(application); - // Read the application from the data store. - Application result = applications.getApplication(sid); - // Validate the results. - assertTrue(result.getSid().equals(application.getSid())); - assertTrue(result.getFriendlyName().equals(application.getFriendlyName())); - assertTrue(result.getAccountSid().equals(application.getAccountSid())); - assertTrue(result.getApiVersion().equals(application.getApiVersion())); - assertFalse(result.hasVoiceCallerIdLookup()); - assertTrue(result.getVoiceUrl().equals(application.getVoiceUrl())); - assertTrue(result.getVoiceMethod().equals(application.getVoiceMethod())); - assertTrue(result.getVoiceFallbackUrl().equals(application.getVoiceFallbackUrl())); - assertTrue(result.getVoiceFallbackMethod().equals(application.getVoiceFallbackMethod())); - assertTrue(result.getStatusCallback().equals(application.getStatusCallback())); - assertTrue(result.getStatusCallbackMethod().equals(application.getStatusCallbackMethod())); - assertTrue(result.getSmsUrl().equals(application.getSmsUrl())); - assertTrue(result.getSmsMethod().equals(application.getSmsMethod())); - assertTrue(result.getSmsFallbackUrl().equals(application.getSmsFallbackUrl())); - assertTrue(result.getSmsFallbackMethod().equals(application.getSmsFallbackMethod())); - assertTrue(result.getSmsStatusCallback().equals(application.getSmsStatusCallback())); - assertTrue(result.getUri().equals(application.getUri())); - // Update the application. - url = URI.create("http://127.0.0.1:8080/restcomm/demos/world-hello.xml"); - method = "POST"; - application = application.setFriendlyName("Application Test"); - application = application.setVoiceCallerIdLookup(true); - application = application.setVoiceUrl(url); - application = application.setVoiceMethod(method); - application = application.setVoiceFallbackUrl(url); - application = application.setVoiceFallbackMethod(method); - application = application.setStatusCallback(url); - application = application.setStatusCallbackMethod(method); - application = application.setSmsUrl(url); - application = application.setSmsMethod(method); - application = application.setSmsFallbackUrl(url); - application = application.setSmsFallbackMethod(method); - application = application.setSmsStatusCallback(url); - applications.updateApplication(application); - // Read the updated application from the data store. - result = applications.getApplication(sid); - // Validate the results. - assertTrue(result.getSid().equals(application.getSid())); - assertTrue(result.getFriendlyName().equals(application.getFriendlyName())); - assertTrue(result.getAccountSid().equals(application.getAccountSid())); - assertTrue(result.getApiVersion().equals(application.getApiVersion())); - assertTrue(result.hasVoiceCallerIdLookup()); - assertTrue(result.getVoiceUrl().equals(application.getVoiceUrl())); - assertTrue(result.getVoiceMethod().equals(application.getVoiceMethod())); - assertTrue(result.getVoiceFallbackUrl().equals(application.getVoiceFallbackUrl())); - assertTrue(result.getVoiceFallbackMethod().equals(application.getVoiceFallbackMethod())); - assertTrue(result.getStatusCallback().equals(application.getStatusCallback())); - assertTrue(result.getStatusCallbackMethod().equals(application.getStatusCallbackMethod())); - assertTrue(result.getSmsUrl().equals(application.getSmsUrl())); - assertTrue(result.getSmsMethod().equals(application.getSmsMethod())); - assertTrue(result.getSmsFallbackUrl().equals(application.getSmsFallbackUrl())); - assertTrue(result.getSmsFallbackMethod().equals(application.getSmsFallbackMethod())); - assertTrue(result.getSmsStatusCallback().equals(application.getSmsStatusCallback())); - assertTrue(result.getUri().equals(application.getUri())); - // Delete the application. - applications.removeApplication(sid); - // Validate that the application was removed. - assertTrue(applications.getApplication(sid) == null); - } - - @Test - public void removeByAccountSid() { - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid sid = Sid.generate(Sid.Type.APPLICATION); - URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - String method = "GET"; - final Application.Builder builder = Application.builder(); - builder.setSid(sid); - builder.setFriendlyName("Test Application"); - builder.setAccountSid(account); - builder.setApiVersion("2012-04-24"); - builder.setHasVoiceCallerIdLookup(false); - builder.setVoiceUrl(url); - builder.setVoiceMethod(method); - builder.setVoiceFallbackUrl(url); - builder.setVoiceFallbackMethod(method); - builder.setStatusCallback(url); - builder.setStatusCallbackMethod(method); - builder.setSmsUrl(url); - builder.setSmsMethod(method); - builder.setSmsFallbackUrl(url); - builder.setSmsFallbackMethod(method); - builder.setSmsStatusCallback(url); - builder.setUri(url); - Application application = builder.build(); - final ApplicationsDao applications = manager.getApplicationsDao(); - // Create a new application in the data store. - applications.addApplication(application); - assertTrue(applications.getApplications(account).size() == 1); - // Delete the application. - applications.removeApplications(account); - assertTrue(applications.getApplications(account).size() == 0); - } -} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/CallDetailRecordsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/CallDetailRecordsDaoTest.java deleted file mode 100644 index 016305a75a..0000000000 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/CallDetailRecordsDaoTest.java +++ /dev/null @@ -1,347 +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.mobicents.servlet.restcomm.dao.mybatis; - -import static org.junit.Assert.*; - -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.util.Currency; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; -import org.joda.time.DateTime; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public class CallDetailRecordsDaoTest { - private static MybatisDaoManager manager; - - public CallDetailRecordsDaoTest() { - super(); - } - - @Before - public void before() { - final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final SqlSessionFactory factory = builder.build(data); - manager = new MybatisDaoManager(); - manager.start(factory); - } - - @After - public void after() { - manager.shutdown(); - } - - @Test - public void createReadUpdateDelete() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("USD")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Read the CDR from the data store. - CallDetailRecord result = cdrs.getCallDetailRecord(sid); - // Validate the results. - assertTrue(result.getSid().equals(cdr.getSid())); - assertTrue(result.getParentCallSid().equals(cdr.getParentCallSid())); - assertTrue(result.getDateCreated().equals(cdr.getDateCreated())); - assertTrue(result.getAccountSid().equals(cdr.getAccountSid())); - assertTrue(result.getTo().equals(cdr.getTo())); - assertTrue(result.getFrom().equals(cdr.getFrom())); - assertTrue(result.getPhoneNumberSid().equals(cdr.getPhoneNumberSid())); - assertTrue(result.getStatus().equals(cdr.getStatus())); - assertTrue(result.getStartTime().equals(cdr.getStartTime())); - assertTrue(result.getEndTime().equals(cdr.getEndTime())); - assertTrue(result.getDuration().equals(cdr.getDuration())); - assertTrue(result.getPrice().equals(cdr.getPrice())); - assertTrue(result.getPriceUnit().equals(cdr.getPriceUnit())); - assertTrue(result.getDirection().equals(cdr.getDirection())); - assertTrue(result.getApiVersion().equals(cdr.getApiVersion())); - assertTrue(result.getCallerName().equals(cdr.getCallerName())); - assertTrue(result.getUri().equals(cdr.getUri())); - // Update the CDR. - cdr = cdr.setDuration(2); - cdr = cdr.setPrice(new BigDecimal("1.00")); - cdr = cdr.setStatus("in-progress"); - cdrs.updateCallDetailRecord(cdr); - // Read the updated CDR from the data store. - result = cdrs.getCallDetailRecord(sid); - // Validate the results. - assertTrue(result.getStatus().equals(cdr.getStatus())); - assertTrue(result.getDuration().equals(cdr.getDuration())); - assertTrue(result.getPrice().equals(cdr.getPrice())); - assertTrue(result.getPriceUnit().equals(cdr.getPriceUnit())); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDR was removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } - - @Test - public void testReadDeleteByAccount() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("JPY")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecords(account).size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecords(account); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecords(account).size() == 0); - } - - public void testReadByRecipient() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("EUR")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecordsByRecipient("+12223334444").size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } - - public void testReadBySender() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("USD")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecordsByRecipient("+17778889999").size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } - - public void testReadByStatus() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("CZK")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecordsByStatus("queued").size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } - - public void testReadByStartTime() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - final DateTime now = DateTime.now(); - builder.setStartTime(now); - builder.setEndTime(now); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("AUD")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecordsByStartTime(now).size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } - - public void testReadByParentCall() { - final Sid sid = Sid.generate(Sid.Type.CALL); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final Sid parent = Sid.generate(Sid.Type.CALL); - final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); - final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(sid); - builder.setParentCallSid(parent); - builder.setDateCreated(DateTime.now()); - builder.setAccountSid(account); - builder.setTo("+12223334444"); - builder.setFrom("+17778889999"); - builder.setPhoneNumberSid(phone); - builder.setStatus("queued"); - builder.setStartTime(DateTime.now()); - builder.setEndTime(DateTime.now()); - builder.setDuration(1); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("GBP")); - builder.setDirection("outbound-api"); - builder.setApiVersion("2012-04-24"); - builder.setCallerName("Alice"); - builder.setUri(url); - CallDetailRecord cdr = builder.build(); - final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); - // Create a new CDR in the data store. - cdrs.addCallDetailRecord(cdr); - // Validate the results. - assertTrue(cdrs.getCallDetailRecordsByParentCall(parent).size() == 1); - // Delete the CDR. - cdrs.removeCallDetailRecord(sid); - // Validate that the CDRs were removed. - assertTrue(cdrs.getCallDetailRecord(sid) == null); - } -} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/IncomingPhoneNumbersDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/IncomingPhoneNumbersDaoTest.java deleted file mode 100644 index 0ec1efe02f..0000000000 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/IncomingPhoneNumbersDaoTest.java +++ /dev/null @@ -1,238 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.io.InputStream; -import java.net.URI; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; - -import org.junit.After; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; - -import org.mobicents.servlet.restcomm.dao.IncomingPhoneNumbersDao; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public class IncomingPhoneNumbersDaoTest { - private static MybatisDaoManager manager; - - public IncomingPhoneNumbersDaoTest() { - super(); - } - - @Before - public void before() { - final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final SqlSessionFactory factory = builder.build(data); - manager = new MybatisDaoManager(); - manager.start(factory); - } - - @After - public void after() { - manager.shutdown(); - } - - @Test - public void createReadUpdateDelete() { - final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); - Sid account = Sid.generate(Sid.Type.ACCOUNT); - Sid application = Sid.generate(Sid.Type.APPLICATION); - URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - String method = "GET"; - final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); - builder.setSid(sid); - builder.setFriendlyName("Incoming Phone Number Test"); - builder.setAccountSid(account); - builder.setPhoneNumber("+12223334444"); - builder.setApiVersion("2012-04-24"); - builder.setHasVoiceCallerIdLookup(false); - builder.setVoiceUrl(url); - builder.setVoiceMethod(method); - builder.setVoiceFallbackUrl(url); - builder.setVoiceFallbackMethod(method); - builder.setStatusCallback(url); - builder.setStatusCallbackMethod(method); - builder.setVoiceApplicationSid(application); - builder.setSmsUrl(url); - builder.setSmsMethod(method); - builder.setSmsFallbackUrl(url); - builder.setSmsFallbackMethod(method); - builder.setSmsApplicationSid(application); - builder.setUri(url); - IncomingPhoneNumber number = builder.build(); - final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); - // Create a new incoming phone number in the data store. - numbers.addIncomingPhoneNumber(number); - // Read the incoming phone number from the data store. - IncomingPhoneNumber result = numbers.getIncomingPhoneNumber(sid); - // Validate the results. - assertTrue(result.getSid().equals(number.getSid())); - assertTrue(result.getFriendlyName().equals(number.getFriendlyName())); - assertTrue(result.getAccountSid().equals(number.getAccountSid())); - assertTrue(result.getPhoneNumber().equals(number.getPhoneNumber())); - assertTrue(result.getApiVersion().equals(number.getApiVersion())); - assertFalse(result.hasVoiceCallerIdLookup()); - assertTrue(result.getVoiceUrl().equals(number.getVoiceUrl())); - assertTrue(result.getVoiceMethod().equals(number.getVoiceMethod())); - assertTrue(result.getVoiceFallbackUrl().equals(number.getVoiceFallbackUrl())); - assertTrue(result.getVoiceFallbackMethod().equals(number.getVoiceFallbackMethod())); - assertTrue(result.getStatusCallback().equals(number.getStatusCallback())); - assertTrue(result.getStatusCallbackMethod().equals(number.getStatusCallbackMethod())); - assertTrue(result.getVoiceApplicationSid().equals(number.getVoiceApplicationSid())); - assertTrue(result.getSmsUrl().equals(number.getSmsUrl())); - assertTrue(result.getSmsMethod().equals(number.getSmsMethod())); - assertTrue(result.getSmsFallbackUrl().equals(number.getSmsFallbackUrl())); - assertTrue(result.getSmsFallbackMethod().equals(number.getSmsFallbackMethod())); - assertTrue(result.getSmsApplicationSid().equals(number.getSmsApplicationSid())); - assertTrue(result.getUri().equals(number.getUri())); - // Update the incoming phone number. - application = Sid.generate(Sid.Type.APPLICATION); - url = URI.create("http://127.0.0.1:8080/restcomm/demos/world-hello.xml"); - method = "POST"; - number.setFriendlyName("Test Application"); - number.setHasVoiceCallerIdLookup(true); - number.setVoiceUrl(url); - number.setVoiceMethod(method); - number.setVoiceFallbackUrl(url); - number.setVoiceFallbackMethod(method); - number.setStatusCallback(url); - number.setStatusCallbackMethod(method); - number.setVoiceApplicationSid(application); - number.setSmsUrl(url); - number.setSmsMethod(method); - number.setSmsFallbackUrl(url); - number.setSmsFallbackMethod(method); - number.setSmsApplicationSid(application); - numbers.updateIncomingPhoneNumber(number); - // Read the updated application from the data store. - result = numbers.getIncomingPhoneNumber(sid); - // Validate the results. - assertTrue(result.getSid().equals(number.getSid())); - assertTrue(result.getFriendlyName().equals(number.getFriendlyName())); - assertTrue(result.getAccountSid().equals(number.getAccountSid())); - assertTrue(result.getPhoneNumber().equals(number.getPhoneNumber())); - assertTrue(result.getApiVersion().equals(number.getApiVersion())); - assertTrue(result.hasVoiceCallerIdLookup()); - assertTrue(result.getVoiceUrl().equals(number.getVoiceUrl())); - assertTrue(result.getVoiceMethod().equals(number.getVoiceMethod())); - assertTrue(result.getVoiceFallbackUrl().equals(number.getVoiceFallbackUrl())); - assertTrue(result.getVoiceFallbackMethod().equals(number.getVoiceFallbackMethod())); - assertTrue(result.getStatusCallback().equals(number.getStatusCallback())); - assertTrue(result.getStatusCallbackMethod().equals(number.getStatusCallbackMethod())); - assertTrue(result.getVoiceApplicationSid().equals(number.getVoiceApplicationSid())); - assertTrue(result.getSmsUrl().equals(number.getSmsUrl())); - assertTrue(result.getSmsMethod().equals(number.getSmsMethod())); - assertTrue(result.getSmsFallbackUrl().equals(number.getSmsFallbackUrl())); - assertTrue(result.getSmsFallbackMethod().equals(number.getSmsFallbackMethod())); - assertTrue(result.getSmsApplicationSid().equals(number.getSmsApplicationSid())); - assertTrue(result.getUri().equals(number.getUri())); - // Delete the incoming phone number. - numbers.removeIncomingPhoneNumber(sid); - // Validate that the incoming phone number was removed. - assertTrue(numbers.getIncomingPhoneNumber(sid) == null); - } - - @Test - public void getByPhoneNumber() { - final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); - Sid account = Sid.generate(Sid.Type.ACCOUNT); - Sid application = Sid.generate(Sid.Type.APPLICATION); - URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - String method = "GET"; - final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); - builder.setSid(sid); - builder.setFriendlyName("Incoming Phone Number Test"); - builder.setAccountSid(account); - builder.setPhoneNumber("+12223334444"); - builder.setApiVersion("2012-04-24"); - builder.setHasVoiceCallerIdLookup(false); - builder.setVoiceUrl(url); - builder.setVoiceMethod(method); - builder.setVoiceFallbackUrl(url); - builder.setVoiceFallbackMethod(method); - builder.setStatusCallback(url); - builder.setStatusCallbackMethod(method); - builder.setVoiceApplicationSid(application); - builder.setSmsUrl(url); - builder.setSmsMethod(method); - builder.setSmsFallbackUrl(url); - builder.setSmsFallbackMethod(method); - builder.setSmsApplicationSid(application); - builder.setUri(url); - IncomingPhoneNumber number = builder.build(); - final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); - // Create a new incoming phone number in the data store. - numbers.addIncomingPhoneNumber(number); - // Read the incoming phone number from the data store. - IncomingPhoneNumber result = numbers.getIncomingPhoneNumber("+12223334444"); - assert (result != null); - assertTrue(result.getSid().equals(number.getSid())); - // Delete the incoming phone number. - numbers.removeIncomingPhoneNumber(sid); - // Validate that the incoming phone number was removed. - assertTrue(numbers.getIncomingPhoneNumber(sid) == null); - } - - @Test - public void removeByAccountSid() { - final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); - Sid account = Sid.generate(Sid.Type.ACCOUNT); - Sid application = Sid.generate(Sid.Type.APPLICATION); - URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); - String method = "GET"; - final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); - builder.setSid(sid); - builder.setFriendlyName("Incoming Phone Number Test"); - builder.setAccountSid(account); - builder.setPhoneNumber("+12223334444"); - builder.setApiVersion("2012-04-24"); - builder.setHasVoiceCallerIdLookup(false); - builder.setVoiceUrl(url); - builder.setVoiceMethod(method); - builder.setVoiceFallbackUrl(url); - builder.setVoiceFallbackMethod(method); - builder.setStatusCallback(url); - builder.setStatusCallbackMethod(method); - builder.setVoiceApplicationSid(application); - builder.setSmsUrl(url); - builder.setSmsMethod(method); - builder.setSmsFallbackUrl(url); - builder.setSmsFallbackMethod(method); - builder.setSmsApplicationSid(application); - builder.setUri(url); - IncomingPhoneNumber number = builder.build(); - final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); - // Create a new incoming phone number in the data store. - numbers.addIncomingPhoneNumber(number); - assertTrue(numbers.getIncomingPhoneNumbers(account).size() == 1); - // Delete the incoming phone number. - numbers.removeIncomingPhoneNumbers(account); - assertTrue(numbers.getIncomingPhoneNumbers(account).size() == 0); - } -} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/SmsMessagesDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/SmsMessagesDaoTest.java deleted file mode 100644 index 6a297a23c8..0000000000 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/SmsMessagesDaoTest.java +++ /dev/null @@ -1,144 +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.mobicents.servlet.restcomm.dao.mybatis; - -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.util.Currency; - -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; -import org.joda.time.DateTime; -import org.junit.After; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class SmsMessagesDaoTest { - private static MybatisDaoManager manager; - - public SmsMessagesDaoTest() { - super(); - } - - @Before - public void before() { - final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); - final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - final SqlSessionFactory factory = builder.build(data); - manager = new MybatisDaoManager(); - manager.start(factory); - } - - @After - public void after() { - manager.shutdown(); - } - - @Test - public void createReadUpdateDelete() { - final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - final URI url = URI.create("2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json"); - final SmsMessage.Builder builder = SmsMessage.builder(); - builder.setSid(sid); - builder.setAccountSid(account); - builder.setApiVersion("2012-04-24"); - builder.setRecipient("+12223334444"); - builder.setSender("+17778889999"); - builder.setBody("Hello World!"); - builder.setStatus(SmsMessage.Status.SENDING); - builder.setDirection(SmsMessage.Direction.INBOUND); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("USD")); - builder.setUri(url); - SmsMessage message = builder.build(); - final SmsMessagesDao messages = manager.getSmsMessagesDao(); - // Create a new sms message in the data store. - messages.addSmsMessage(message); - // Read the message from the data store. - SmsMessage result = messages.getSmsMessage(sid); - // Validate the results. - assertTrue(result.getSid().equals(message.getSid())); - assertTrue(result.getAccountSid().equals(message.getAccountSid())); - assertTrue(result.getApiVersion().equals(message.getApiVersion())); - assertTrue(result.getDateSent() == message.getDateSent()); - assertTrue(result.getRecipient().equals(message.getRecipient())); - assertTrue(result.getSender().equals(message.getSender())); - assertTrue(result.getBody().equals(message.getBody())); - assertTrue(result.getStatus() == message.getStatus()); - assertTrue(result.getDirection() == message.getDirection()); - assertTrue(result.getPrice().equals(message.getPrice())); - assertTrue(result.getPriceUnit().equals(message.getPriceUnit())); - assertTrue(result.getUri().equals(message.getUri())); - // Update the message. - final DateTime now = DateTime.now(); - message = message.setDateSent(now); - message = message.setStatus(SmsMessage.Status.SENT); - messages.updateSmsMessage(message); - // Read the updated message from the data store. - result = messages.getSmsMessage(sid); - // Validate the results. - assertTrue(result.getDateSent().equals(message.getDateSent())); - assertTrue(result.getStatus() == message.getStatus()); - // Delete the message. - messages.removeSmsMessage(sid); - // Validate that the CDR was removed. - assertTrue(messages.getSmsMessage(sid) == null); - } - - @Test - public void testReadDeleteByAccount() { - final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); - final Sid account = Sid.generate(Sid.Type.ACCOUNT); - DateTime now = DateTime.now(); - final URI url = URI.create("2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json"); - final SmsMessage.Builder builder = SmsMessage.builder(); - builder.setSid(sid); - builder.setAccountSid(account); - builder.setApiVersion("2012-04-24"); - builder.setDateSent(now); - builder.setRecipient("+12223334444"); - builder.setSender("+17778889999"); - builder.setBody("Hello World!"); - builder.setStatus(SmsMessage.Status.SENDING); - builder.setDirection(SmsMessage.Direction.INBOUND); - builder.setPrice(new BigDecimal("0.00")); - builder.setPriceUnit(Currency.getInstance("GBP")); - builder.setUri(url); - SmsMessage message = builder.build(); - final SmsMessagesDao messages = manager.getSmsMessagesDao(); - // Create a new sms message in the data store. - messages.addSmsMessage(message); - // Validate the results. - assertTrue(messages.getSmsMessages(account).size() == 1); - // Delete the message. - messages.removeSmsMessages(account); - // Validate the results. - assertTrue(messages.getSmsMessages(account).size() == 0); - } -} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/AccountsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/AccountsDaoTest.java new file mode 100644 index 0000000000..6b98fe8568 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/AccountsDaoTest.java @@ -0,0 +1,121 @@ +package org.restcomm.connect.dao.mybatis; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import junit.framework.Assert; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.commons.dao.Sid; + +public class AccountsDaoTest extends DaoTest { + private static MybatisDaoManager manager; + + public AccountsDaoTest() { + super(); + } + + @Before + public void before() throws Exception { + sandboxRoot = createTempDir("accountsTest"); + String mybatisFilesPath = getClass().getResource("/accountsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() throws Exception { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void addAccountTest() throws IllegalArgumentException, URISyntaxException { + AccountsDao dao = manager.getAccountsDao(); + Sid sid = Sid.generate(Sid.Type.ACCOUNT); + dao.addAccount(new Account(sid, new DateTime(), new DateTime(), "test@telestax.com", "Top Level Account", new Sid("AC00000000000000000000000000000000"),Account.Type.FULL,Account.Status.ACTIVE,"77f8c12cc7b8f8423e5c38b035249166","Administrator",new URI("/2012-04-24/Accounts/AC00000000000000000000000000000000"), new Sid("ORafbe225ad37541eba518a74248f0ac4c"))); + Account account = dao.getAccount(sid); + Assert.assertNotNull("Account not found",account); + Assert.assertNotNull(account.getOrganizationSid()); + } + + @Test + public void readAccount() { + AccountsDao dao = manager.getAccountsDao(); + Account account = dao.getAccount(new Sid("AC00000000000000000000000000000000")); + Assert.assertNotNull("Account not found",account); + } + + @Test + public void nestedSubAccountRetrieval() { + // retrieve all sub-accounts of AC00000000000000000000000000000000 + AccountsDao dao = manager.getAccountsDao(); + Sid parentSid = new Sid("AC00000000000000000000000000000000"); + List sidList = dao.getSubAccountSidsRecursive(parentSid); + Assert.assertEquals("Invalid number of subaccounts returned",5, sidList.size()); + // a parent with no sub-accounts should get zero + parentSid = new Sid("AC99999999999999999999999999999999"); + sidList = dao.getSubAccountSidsRecursive(parentSid); + Assert.assertEquals("No sub-account sids should be returned", 0, sidList.size()); + // check 2nd-level parents too + parentSid = new Sid("AC10000000000000000000000000000000"); + sidList = dao.getSubAccountSidsRecursive(parentSid); + Assert.assertEquals("Invalid number of sub-account for 2nd level perent", 3, sidList.size()); + // check third-level perent too + parentSid = new Sid("AC11000000000000000000000000000000"); + sidList = dao.getSubAccountSidsRecursive(parentSid); + Assert.assertEquals("Invalid number of sub-account for 3rd level perent", 1, sidList.size()); + // test behaviour for non-existing parents. An empty list should be returned + parentSid = new Sid("AC59494830204948392023934839392092"); // this does not exist + sidList = dao.getSubAccountSidsRecursive(parentSid); + Assert.assertEquals("Invalid number of sub-account for 3rd level perent", 0, sidList.size()); + } + + @Test + public void accountAncestorsRetrieval() throws AccountHierarchyDepthCrossed { + AccountsDao dao = manager.getAccountsDao(); + + List ancestorSids = dao.getAccountLineage(new Sid("AC11000000000000000000000000000000")); + Assert.assertEquals(2, ancestorSids.size()); + // check last account returned is the top-level + Assert.assertEquals("AC00000000000000000000000000000000", ancestorSids.get(ancestorSids.size()-1)); + // also check the overloaded version + Account account = dao.getAccount("AC11000000000000000000000000000000"); + ancestorSids = dao.getAccountLineage(account); + Assert.assertEquals(2, ancestorSids.size()); + Assert.assertEquals("AC00000000000000000000000000000000", ancestorSids.get(ancestorSids.size()-1)); + + // for top level accounts an empty list should be returned + ancestorSids = dao.getAccountLineage(new Sid("AC00000000000000000000000000000000")); + Assert.assertEquals(0, ancestorSids.size()); + Account topLevelAccount = dao.getAccount("AC00000000000000000000000000000000"); + ancestorSids = dao.getAccountLineage(topLevelAccount); + Assert.assertEquals(0, ancestorSids.size()); + + Assert.assertNull(dao.getAccountLineage((Sid)null)); + } + + @Test(expected=AccountHierarchyDepthCrossed.class) + public void checkAccountRecursionLimit() throws AccountHierarchyDepthCrossed { + AccountsDao dao = manager.getAccountsDao(); + // try to retrieve the lineage for an account that is in the forth level + List ancestorSids = dao.getAccountLineage(new Sid("AC11100000000000000000000000000000")); + } + +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationRetrievalTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationRetrievalTest.java new file mode 100644 index 0000000000..4946375f4f --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationRetrievalTest.java @@ -0,0 +1,108 @@ +/* + * 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.dao.mybatis; + +import junit.framework.Assert; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.entities.Application; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class ApplicationRetrievalTest extends DaoTest { + private static MybatisDaoManager manager; + + public ApplicationRetrievalTest() { + super(); + } + + @Before + public void before() throws Exception { + sandboxRoot = createTempDir("applicationRetrievalTest"); + String mybatisFilesPath = getClass().getResource("/applicationsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() throws Exception { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void retrieveApplications() { + ApplicationsDao dao = manager.getApplicationsDao(); + List apps = dao.getApplications(new Sid("ACae6e420f425248d6a26948c17a9e2acf")); + Assert.assertEquals(5, apps.size()); + } + + /** + * PN00000000000000000000000000000001 is bound to AP73926e7113fa4d95981aa96b76eca854 (sms) + * PN00000000000000000000000000000002 is bound to AP73926e7113fa4d95981aa96b76eca854 (both sms+ussd) + * PN00000000000000000000000000000003 is bound to AP00000000000000000000000000000005. The number belong sto other account + * AP00000000000000000000000000000006 belongs to other account + */ + @Test + public void retrieveApplicationsAndTheirNumbers() { + ApplicationsDao dao = manager.getApplicationsDao(); + List apps = dao.getApplicationsWithNumbers(new Sid("ACae6e420f425248d6a26948c17a9e2acf")); + + Assert.assertEquals(5, apps.size()); + Assert.assertNotNull(searchApplicationBySid(new Sid("AP73926e7113fa4d95981aa96b76eca854"),apps).getNumbers()); + // applications bound with many numbers are property returned + Assert.assertEquals("Three (3) numbers should be bound to this application", 3, searchApplicationBySid(new Sid("AP73926e7113fa4d95981aa96b76eca854"),apps).getNumbers().size()); + // applications bound with no numbers are properly returned + Assert.assertNull(searchApplicationBySid(new Sid("AP00000000000000000000000000000004"),apps).getNumbers()); + // applications bound to numbers that belong to different account should not be returned (for now at least) + Assert.assertNull(searchApplicationBySid(new Sid("AP00000000000000000000000000000005"),apps).getNumbers()); + + } + + private Application searchApplicationBySid(Sid sid, List apps) { + if (apps != null) { + int i = 0; + while (i < apps.size()) { + if (apps.get(i).getSid().equals(sid)) + return apps.get(i); + i++; + } + } + return null; // nothing found + + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationsDaoTest.java new file mode 100644 index 0000000000..d9bbaefeff --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ApplicationsDaoTest.java @@ -0,0 +1,140 @@ +/* + * 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.dao.mybatis; + +import java.io.InputStream; +import java.net.URI; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; + +import org.junit.After; +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public final class ApplicationsDaoTest { + private static MybatisDaoManager manager; + + public ApplicationsDaoTest() { + super(); + } + + @Before + public void before() { + final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void createReadUpdateDelete() { + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid sid = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + Application.Kind kind = Application.Kind.VOICE; + final Application.Builder builder = Application.builder(); + builder.setSid(sid); + builder.setFriendlyName("Test Application"); + builder.setAccountSid(account); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setUri(url); + builder.setRcmlUrl(url); + builder.setKind(kind); + Application application = builder.build(); + final ApplicationsDao applications = manager.getApplicationsDao(); + // Create a new application in the data store. + applications.addApplication(application); + // Read the application from the data store. + Application result = applications.getApplication(sid); + // Validate the results. + assertTrue(result.getSid().equals(application.getSid())); + assertTrue(result.getFriendlyName().equals(application.getFriendlyName())); + assertTrue(result.getAccountSid().equals(application.getAccountSid())); + assertTrue(result.getApiVersion().equals(application.getApiVersion())); + assertFalse(result.hasVoiceCallerIdLookup()); + assertTrue(result.getUri().equals(application.getUri())); + assertTrue(result.getRcmlUrl().equals(application.getRcmlUrl())); + assertTrue(result.getKind().toString().equals(application.getKind().toString())); + // Update the application. + url = URI.create("http://127.0.0.1:8080/restcomm/demos/world-hello.xml"); + kind = Application.Kind.SMS; + application = application.setFriendlyName("Application Test"); + application = application.setVoiceCallerIdLookup(true); + application = application.setRcmlUrl(url); + application = application.setKind(kind); + applications.updateApplication(application); + // Read the updated application from the data store. + result = applications.getApplication(sid); + // Validate the results. + assertTrue(result.getSid().equals(application.getSid())); + assertTrue(result.getFriendlyName().equals(application.getFriendlyName())); + assertTrue(result.getAccountSid().equals(application.getAccountSid())); + assertTrue(result.getApiVersion().equals(application.getApiVersion())); + assertTrue(result.hasVoiceCallerIdLookup()); + assertTrue(result.getUri().equals(application.getUri())); + assertTrue(result.getRcmlUrl().equals(application.getRcmlUrl())); + assertTrue(result.getKind().toString().equals(application.getKind().toString())); + // Delete the application. + applications.removeApplication(sid); + // Validate that the application was removed. + assertTrue(applications.getApplication(sid) == null); + } + + @Test + public void removeByAccountSid() { + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid sid = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + Application.Kind kind = Application.Kind.VOICE; + final Application.Builder builder = Application.builder(); + builder.setSid(sid); + builder.setFriendlyName("Test Application"); + builder.setAccountSid(account); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setUri(url); + builder.setRcmlUrl(url); + builder.setKind(kind); + Application application = builder.build(); + final ApplicationsDao applications = manager.getApplicationsDao(); + // Create a new application in the data store. + applications.addApplication(application); + assertTrue(applications.getApplications(account).size() == 1); + // Delete the application. + applications.removeApplications(account); + assertTrue(applications.getApplications(account).size() == 0); + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/CallDetailRecordsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/CallDetailRecordsDaoTest.java new file mode 100644 index 0000000000..96956b2577 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/CallDetailRecordsDaoTest.java @@ -0,0 +1,458 @@ +/* + * 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.dao.mybatis; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Currency; +import java.util.List; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordFilter; + +import junit.framework.Assert; +import org.junit.Rule; +import org.junit.rules.TestName; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public class CallDetailRecordsDaoTest extends DaoTest { + @Rule public TestName name = new TestName(); + + private static MybatisDaoManager manager; + + public CallDetailRecordsDaoTest() { + super(); + } + + @Before + public void before() throws Exception { + //use testmethod name to further ensure uniqueness of tmp dir + sandboxRoot = createTempDir("cdrTest" + name.getMethodName()); + String mybatisFilesPath = getClass().getResource("/callDetailRecordsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void createReadUpdateDelete() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId.toString()); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("USD")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Read the CDR from the data store. + CallDetailRecord result = cdrs.getCallDetailRecord(sid); + // Validate the results. + assertTrue(result.getSid().equals(cdr.getSid())); + assertTrue(result.getParentCallSid().equals(cdr.getParentCallSid())); + assertTrue(result.getDateCreated().equals(cdr.getDateCreated())); + assertTrue(result.getAccountSid().equals(cdr.getAccountSid())); + assertTrue(result.getTo().equals(cdr.getTo())); + assertTrue(result.getFrom().equals(cdr.getFrom())); + assertTrue(result.getPhoneNumberSid().equals(cdr.getPhoneNumberSid())); + assertTrue(result.getStatus().equals(cdr.getStatus())); + assertTrue(result.getStartTime().equals(cdr.getStartTime())); + assertTrue(result.getEndTime().equals(cdr.getEndTime())); + assertTrue(result.getDuration().equals(cdr.getDuration())); + assertTrue(result.getPrice().equals(cdr.getPrice())); + assertTrue(result.getPriceUnit().equals(cdr.getPriceUnit())); + assertTrue(result.getDirection().equals(cdr.getDirection())); + assertTrue(result.getApiVersion().equals(cdr.getApiVersion())); + assertTrue(result.getCallerName().equals(cdr.getCallerName())); + assertTrue(result.getUri().equals(cdr.getUri())); + // Update the CDR. + cdr = cdr.setDuration(2); + cdr = cdr.setPrice(new BigDecimal("1.00")); + cdr = cdr.setStatus("in-progress"); + cdrs.updateCallDetailRecord(cdr); + // Read the updated CDR from the data store. + result = cdrs.getCallDetailRecord(sid); + // Validate the results. + assertTrue(result.getStatus().equals(cdr.getStatus())); + assertTrue(result.getDuration().equals(cdr.getDuration())); + assertTrue(result.getPrice().equals(cdr.getPrice())); + assertTrue(result.getPriceUnit().equals(cdr.getPriceUnit())); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDR was removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + @Test + public void testReadDeleteByAccount() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("JPY")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByAccountSid(account).size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecords(account); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecordsByAccountSid(account).size() == 0); + } + + public void testReadByRecipient() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("EUR")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByRecipient("+12223334444").size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + public void testReadBySender() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("USD")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByRecipient("+17778889999").size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + public void testReadByStatus() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("CZK")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByStatus("queued").size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + @Test + public void testReadByStartTime() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + final DateTime now = DateTime.now(); + builder.setStartTime(now); + builder.setEndTime(now); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("AUD")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByStartTime(now).size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + @Test + public void testReadByEndTime() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + final DateTime now = DateTime.now(); + builder.setStartTime(now); + builder.setEndTime(now); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("AUD")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + int beforeAdding = cdrs.getCallDetailRecordsByEndTime(now).size(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results, including the ones matching in the script(10) + assertEquals(beforeAdding + 1, cdrs.getCallDetailRecordsByEndTime(now).size()); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + public void testReadByParentCall() { + final Sid sid = Sid.generate(Sid.Type.CALL); + final String instanceId = Sid.generate(Sid.Type.INSTANCE).toString(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final Sid parent = Sid.generate(Sid.Type.CALL); + final Sid phone = Sid.generate(Sid.Type.PHONE_NUMBER); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(sid); + builder.setInstanceId(instanceId); + builder.setParentCallSid(parent); + builder.setDateCreated(DateTime.now()); + builder.setAccountSid(account); + builder.setTo("+12223334444"); + builder.setFrom("+17778889999"); + builder.setPhoneNumberSid(phone); + builder.setStatus("queued"); + builder.setStartTime(DateTime.now()); + builder.setEndTime(DateTime.now()); + builder.setDuration(1); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("GBP")); + builder.setDirection("outbound-api"); + builder.setApiVersion("2012-04-24"); + builder.setCallerName("Alice"); + builder.setUri(url); + CallDetailRecord cdr = builder.build(); + final CallDetailRecordsDao cdrs = manager.getCallDetailRecordsDao(); + // Create a new CDR in the data store. + cdrs.addCallDetailRecord(cdr); + // Validate the results. + assertTrue(cdrs.getCallDetailRecordsByParentCall(parent).size() == 1); + // Delete the CDR. + cdrs.removeCallDetailRecord(sid); + // Validate that the CDRs were removed. + assertTrue(cdrs.getCallDetailRecord(sid) == null); + } + + @Test + public void retrieveAccountCdrsRecursively() throws ParseException { + CallDetailRecordsDao dao = manager.getCallDetailRecordsDao(); + + /* + Sample data summary + + 100 calls in total + 12 calls belong to AC00000000000000000000000000000000 + 5 calls belong to AC11111111111111111111111111111111 + 8 calls belong to AC22222222222222222222222222222222 + */ + + // read from a single account but using the 'accountSidSet' interface + List accountSidSet = new ArrayList(); + accountSidSet.add("AC00000000000000000000000000000000"); + CallDetailRecordFilter filter = new CallDetailRecordFilter(null, accountSidSet, null, null, null, null, null, null, null, null, null); + Assert.assertEquals(12, dao.getTotalCallDetailRecords(filter).intValue()); + // read cdrs of three accounts + accountSidSet.add("AC00000000000000000000000000000000"); + accountSidSet.add("AC11111111111111111111111111111111"); + accountSidSet.add("AC22222222222222222222222222222222"); + Assert.assertEquals(25, dao.getTotalCallDetailRecords(filter).intValue()); + // pass an empty accountSid set + accountSidSet.clear(); + Assert.assertEquals(0, dao.getTotalCallDetailRecords(filter).intValue()); + // if both an accountSid and a accountSid set are passed, only accountSidSet is taken into account + filter = new CallDetailRecordFilter("ACae6e420f425248d6a26948c17a9e2acf", accountSidSet, null, null, null, null, null, null, null, null, null); + accountSidSet.add("AC00000000000000000000000000000000"); + accountSidSet.add("AC11111111111111111111111111111111"); + accountSidSet.add("AC22222222222222222222222222222222"); + Assert.assertEquals(25, dao.getTotalCallDetailRecords(filter).intValue()); + // if no (null) accountSidSet is passed the method still works + filter = new CallDetailRecordFilter("AC00000000000000000000000000000000", null, null, null, null, null, null, null, null, null, null); + Assert.assertEquals(12, dao.getTotalCallDetailRecords(filter).intValue()); + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ClientsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ClientsDaoTest.java similarity index 86% rename from restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ClientsDaoTest.java rename to restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ClientsDaoTest.java index b6416ddcfb..77b70b384b 100644 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/ClientsDaoTest.java +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ClientsDaoTest.java @@ -17,25 +17,28 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.io.InputStream; import java.net.URI; +import java.net.URISyntaxException; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; - +import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import static org.junit.Assert.*; import org.junit.Test; - -import org.mobicents.servlet.restcomm.dao.ClientsDao; -import org.mobicents.servlet.restcomm.entities.Client; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria farooq */ public final class ClientsDaoTest { private static MybatisDaoManager manager; @@ -79,6 +82,7 @@ public void createReadUpdateDelete() { builder.setVoiceFallbackMethod(method); builder.setVoiceApplicationSid(application); builder.setUri(url); + builder.setPushClientIdentity(sid.toString()); Client client = builder.build(); final ClientsDao clients = manager.getClientsDao(); // Create a new client in the data store. @@ -99,10 +103,12 @@ public void createReadUpdateDelete() { assertTrue(result.getVoiceFallbackMethod().equals(client.getVoiceFallbackMethod())); assertTrue(result.getVoiceApplicationSid().equals(client.getVoiceApplicationSid())); assertTrue(result.getUri().equals(client.getUri())); + assertTrue(result.getPushClientIdentity().equals(client.getPushClientIdentity())); // Update the client. application = Sid.generate(Sid.Type.APPLICATION); url = URI.create("http://127.0.0.1:8080/restcomm/demos/world-hello.xml"); method = "POST"; + String newClientIdentity = "newClientIdentity"; client = client.setFriendlyName("Bob"); client = client.setPassword("4321"); client = client.setStatus(Client.DISABLED); @@ -111,6 +117,7 @@ public void createReadUpdateDelete() { client = client.setVoiceMethod(method); client = client.setVoiceFallbackUrl(url); client = client.setVoiceFallbackMethod(method); + client = client.setPushClientIdentity(newClientIdentity); clients.updateClient(client); // Read the updated client from the data store. result = clients.getClient(sid); @@ -124,6 +131,7 @@ public void createReadUpdateDelete() { assertTrue(result.getVoiceFallbackUrl().equals(client.getVoiceFallbackUrl())); assertTrue(result.getVoiceFallbackMethod().equals(client.getVoiceFallbackMethod())); assertTrue(result.getVoiceApplicationSid().equals(client.getVoiceApplicationSid())); + assertTrue(result.getPushClientIdentity().equals(newClientIdentity)); // Delete the client. clients.removeClient(sid); // Validate that the client was removed. @@ -132,14 +140,24 @@ public void createReadUpdateDelete() { @Test public void readByUser() { - final Sid account = Sid.generate(Sid.Type.ACCOUNT); + AccountsDao dao = manager.getAccountsDao(); + Sid accountSid = Sid.generate(Sid.Type.ACCOUNT); + final Sid org = Sid.generate(Sid.Type.ORGANIZATION); + try { + dao.addAccount(new Account(accountSid, new DateTime(), new DateTime(), "test@telestax.com", "Top Level Account", new Sid("AC00000000000000000000000000000000"),Account.Type.FULL,Account.Status.ACTIVE,"77f8c12cc7b8f8423e5c38b035249166","Administrator",new URI("/2012-04-24/Accounts/AC00000000000000000000000000000000"), org)); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + final Sid sid = Sid.generate(Sid.Type.CLIENT); Sid application = Sid.generate(Sid.Type.APPLICATION); URI url = URI.create("hello-world.xml"); String method = "GET"; final Client.Builder builder = Client.builder(); builder.setSid(sid); - builder.setAccountSid(account); + builder.setAccountSid(accountSid); builder.setApiVersion("2012-04-24"); builder.setFriendlyName("Tom"); builder.setLogin("tom"); @@ -156,7 +174,7 @@ public void readByUser() { // Create a new client in the data store. clients.addClient(client); // Read the client from the data store using the user name. - final Client result = clients.getClient("tom"); + final Client result = clients.getClient("tom", org); // Validate the result. assertTrue(result.getSid().equals(client.getSid())); assertTrue(result.getAccountSid().equals(client.getAccountSid())); diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ConfDetailRecordsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ConfDetailRecordsDaoTest.java new file mode 100644 index 0000000000..e1bb55c214 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ConfDetailRecordsDaoTest.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.dao.mybatis; + +import static org.junit.Assert.assertEquals; + +import java.io.InputStream; +import java.net.URI; +import java.util.Properties; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.dao.entities.ConferenceRecordCountFilter; + +public class ConfDetailRecordsDaoTest extends DaoTest { + + @Rule + public TestName testName = new TestName(); + + //RUNNING_INITIALIZING, RUNNING_MODERATOR_ABSENT, RUNNING_MODERATOR_PRESENT, STOPPING, COMPLETED, FAILED + @Rule + public TestName name = new TestName(); + + private static MybatisDaoManager manager; + + public ConfDetailRecordsDaoTest() { + super(); + } + + @Before + public void before() { + final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + Properties props = new Properties(); + props.setProperty("testcase", testName.getMethodName()); + final SqlSessionFactory factory = builder.build(data, props); + manager = new MybatisDaoManager(); + manager.start(factory); + + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void testCountByMsIdAnStatus() throws Exception { + final Sid accountSid = Sid.generate(Sid.Type.ACCOUNT); + + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + + final Sid sid = Sid.generate(Sid.Type.CONFERENCE); + final ConferenceDetailRecord.Builder builder = ConferenceDetailRecord.builder(); + builder.setAccountSid(accountSid); + builder.setApiVersion("2012-04-24"); + builder.setDateCreated(DateTime.now()); + builder.setFriendlyName("myconf"); + builder.setMasterConfernceEndpointId("masterConEndId"); + builder.setMasterIVREndpointId("masterIvrId"); + builder.setMasterMsId("masterMsId"); + builder.setSid(sid); + builder.setStatus("RUNNING_INITIALIZING"); + builder.setUri(url); + ConferenceDetailRecord cdr = builder.build(); + manager.getConferenceDetailRecordsDao().addConferenceDetailRecord(cdr); + + final Sid sid2 = Sid.generate(Sid.Type.CONFERENCE); + final ConferenceDetailRecord.Builder builder2 = ConferenceDetailRecord.builder(); + builder2.setAccountSid(accountSid); + builder2.setApiVersion("2012-04-24"); + builder2.setDateCreated(DateTime.now()); + builder2.setFriendlyName("myconf"); + builder2.setMasterConfernceEndpointId("masterConEndId"); + builder2.setMasterIVREndpointId("masterIvrId"); + builder2.setMasterMsId("masterMsId"); + builder2.setSid(sid2); + builder2.setStatus("RUNNING_MODERATOR_PRESENT"); + builder2.setUri(url); + ConferenceDetailRecord cdr2 = builder2.build(); + manager.getConferenceDetailRecordsDao().addConferenceDetailRecord(cdr2); + + final Sid sid3 = Sid.generate(Sid.Type.CONFERENCE); + final ConferenceDetailRecord.Builder builder3 = ConferenceDetailRecord.builder(); + builder3.setAccountSid(accountSid); + builder3.setApiVersion("2012-04-24"); + builder3.setDateCreated(DateTime.now()); + builder3.setFriendlyName("myconf"); + builder3.setMasterConfernceEndpointId("masterConEndId"); + builder3.setMasterIVREndpointId("masterIvrId"); + builder3.setMasterMsId("masterMsId"); + builder3.setSid(sid3); + builder3.setStatus("COMPLETED"); + builder3.setUri(url); + ConferenceDetailRecord cdr3 = builder3.build(); + manager.getConferenceDetailRecordsDao().addConferenceDetailRecord(cdr3); + + ConferenceRecordCountFilter filter = ConferenceRecordCountFilter.builder(). + byAccountSid(accountSid.toString()). + byMasterMsId("masterMsId") + .byStatus("RUNNING%").build(); + Integer confCount = manager.getConferenceDetailRecordsDao().countByFilter(filter); + assertEquals(Integer.valueOf(2), confCount); + } + + @Test + public void testAddRead() throws Exception { + final Sid accountSid = Sid.generate(Sid.Type.ACCOUNT); + final Sid sid = Sid.generate(Sid.Type.CONFERENCE); + final URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + + final ConferenceDetailRecord.Builder builder = ConferenceDetailRecord.builder(); + builder.setAccountSid(sid); + builder.setApiVersion("2012-04-24"); + builder.setDateCreated(DateTime.now()); + builder.setFriendlyName("myconf"); + builder.setMasterConfernceEndpointId("masterConEndId"); + builder.setMasterIVREndpointId("masterIvrId"); + builder.setMasterMsId("masterMsId"); + builder.setSid(sid); + builder.setStatus("RUNNING_INITIALIZING"); + builder.setUri(url); + ConferenceDetailRecord cdr = builder.build(); + manager.getConferenceDetailRecordsDao().addConferenceDetailRecord(cdr); + ConferenceDetailRecord cdrResult = manager.getConferenceDetailRecordsDao().getConferenceDetailRecord(sid); + assertEquals(cdr.getFriendlyName(), cdrResult.getFriendlyName()); + } + +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/DaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/DaoTest.java new file mode 100644 index 0000000000..c7a5b8d658 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/DaoTest.java @@ -0,0 +1,93 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2014, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it and/or modify + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +package org.restcomm.connect.dao.mybatis; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; + +import java.io.File; +import java.io.IOException; +import java.util.Random; + +/** + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public class DaoTest { + + File sandboxRoot; // rot directory where mybatis files will be created in + + protected static Sid instanceId = Sid.generate(Sid.Type.INSTANCE); + /** + * Create a temporary directory with random name inside the system temporary directory. + * Provide a prefix that will be used when creating the name too. + * + * @param prefix + * @return + */ + public File createTempDir(String prefix) { + String tempDirLocation = generateTempDirName(prefix); + File tempDir = new File(tempDirLocation); + tempDir.mkdir(); + + return tempDir; + } + + private String generateTempDirName(String prefix) { + String tempDirLocationRoot = System.getProperty("java.io.tmpdir"); + Random ran = new Random(); + return tempDirLocationRoot + "/" + prefix + ran.nextInt(10000); + } + + /** + * Remove a temporary directory. Use this to couple createTempDir(). + * + * @param tempDirLocation + */ + public void removeTempDir(String tempDirLocation) { + File tempDir = new File(tempDirLocation); + FileUtils.deleteQuietly(tempDir); + } + + public static void setupSandbox(String mybatisFilesSource, File sandboxDir) throws IOException { + File mybatisDir = new File(mybatisFilesSource); + FileUtils.copyDirectory(mybatisDir, sandboxDir); + // replace mybatis descriptors path inside sandbox mybatis.xml + String mybatisXmlPath = sandboxDir.getAbsolutePath() + "/mybatis.xml"; + String content = FileUtils.readFileToString(new File(mybatisXmlPath)); + content = content.replaceAll("MYBATIS_SANDBOX_PATH",sandboxDir.getAbsolutePath()); + FileUtils.writeStringToFile(new File(sandboxDir.getAbsolutePath() + "/mybatis_updated.xml"),content); + + XMLConfiguration xmlConfiguration = new XMLConfiguration(); + xmlConfiguration.setDelimiterParsingDisabled(true); + xmlConfiguration.setAttributeSplittingDisabled(true); + try { + xmlConfiguration.load("restcomm.xml"); + RestcommConfiguration.createOnce(xmlConfiguration); + RestcommConfiguration.getInstance().getMain().setInstanceId(instanceId.toString()); + } catch (ConfigurationException e) { + e.printStackTrace(); + } + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ExtensionConfigurationDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ExtensionConfigurationDaoTest.java new file mode 100644 index 0000000000..05b8e8a08c --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ExtensionConfigurationDaoTest.java @@ -0,0 +1,368 @@ +package org.restcomm.connect.dao.mybatis; + +import java.io.File; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.restcomm.connect.commons.annotations.UnstableTests; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.api.ExtensionConfiguration; + +import java.io.InputStream; +import java.nio.file.Files; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import java.util.List; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import org.junit.Rule; +import org.junit.rules.TestName; + +/** + * Created by gvagenas on 21/10/2016. + */ +@Category(UnstableTests.class) +public class ExtensionConfigurationDaoTest { + private static MybatisDaoManager manager; + private MybatisExtensionsConfigurationDao extensionsConfigurationDao; + + @Rule + public TestName name = new TestName(); + + private String validJsonObject = "{\n" + + " \"project\": \"Restcomm-Connect\",\n" + + " \"url\": \"http://restcomm.com\",\n" + + " \"open-source\": true,\n" + + " \"scm\": {\n" + + " \"url\": \"https://github.com/RestComm/Restcomm-Connect/\",\n" + + " \"issues\": \"https://github.com/RestComm/Restcomm-Connect/issues\"\n" + + " },\n" + + " \"ci\": {\n" + + " \"name\": \"Jenkins\",\n" + + " \"url\": \"https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\"\n" + + " },\n" + + " \"active\": \"true\"\n" + + "}"; + + private String invalidJsonObject = "{\n" + + " project: Restcomm-Connect,\n" + + " \"url\": \"http://restcomm.com\",\n" + + " \"open-source\": true,\n" + + " \"scm\": {\n" + + " \"url\": \"https://github.com/RestComm/Restcomm-Connect/\",\n" + + " \"issues\": \"https://github.com/RestComm/Restcomm-Connect/issues\"\n" + + " }\n" + + " \"ci\": [\n" + + " {\n" + + " \"name\": \"Jenkins\",\n" + + " \"url\": \"https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\"\n" + + " }\n" + + " \"active\": \"true\"\n" + + "}"; + + private String validXmlDoc = "\n" + + "\n" + + " Restcomm-Connect\n" + + " http://restcomm.com\n" + + " true\n" + + " \n" + + " https://github.com/RestComm/Restcomm-Connect/\n" + + " https://github.com/RestComm/Restcomm-Connect/issues\n" + + " \n" + + " \n" + + " Jenkins\n" + + " https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\n" + + " \n" + + ""; + + private String invalidXmlDoc = "\n" + + "\n" + + " Restcomm-Connect\n" + + " http://restcomm.com\n" + + " true\n" + + " \n" + + " https://github.com/RestComm/Restcomm-Connect/\n" + + " https://github.com/RestComm/Restcomm-Connect/issues\n" + + " \n" + + " \n" + + " Jenkins\n" + + " https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\n" + + " "; + + private String updatedJsonObject = "{\n" + + " \"project\": \"Restcomm-Connect\",\n" + + " \"url\": \"http://restcomm.com\",\n" + + " \"open-source\": true,\n" + + " \"scm\": {\n" + + " \"url\": \"https://github.com/RestComm/Restcomm-Connect/\",\n" + + " \"issues\": \"https://github.com/RestComm/Restcomm-Connect/issues\"\n" + + " },\n" + + " \"ci\": {\n" + + " \"name\": \"Jenkins\",\n" + + " \"url\": \"https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\"\n" + + " },\n" + + " \"active\": \"false\"\n" + + "}"; + + private String updatedXmlDoc = "\n" + + "\n" + + " Restcomm-Connect\n" + + " http://restcomm.com\n" + + " true\n" + + " \n" + + " https://github.com/RestComm/Restcomm-Connect/\n" + + " https://github.com/RestComm/Restcomm-Connect/issues\n" + + " \n" + + " \n" + + " Jenkins\n" + + " https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/\n" + + " \n" + + " true\n" + + ""; + + @Before + public void before() throws Exception{ + //use a different data dir for each test case to provide isolation + Properties properties = new Properties(); + File srcFile = new File("./target/test-classes/data/restcomm.script"); + File theDir = new File("./target/test-classes/data" + name.getMethodName()); + theDir.mkdir(); + File destFile = new File("./target/test-classes/data" + name.getMethodName() + "/restcomm.script"); + + Files.copy(srcFile.toPath(), + destFile.toPath(), REPLACE_EXISTING); + properties.setProperty("data", name.getMethodName()); + + final InputStream data = getClass().getResourceAsStream("/mybatis_pertest.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data,properties); + manager = new MybatisDaoManager(); + manager.start(factory); + extensionsConfigurationDao = (MybatisExtensionsConfigurationDao) manager.getExtensionsConfigurationDao(); + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void testValidJsonDoc() { + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + "testExt", true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + assertEquals(true, extensionsConfigurationDao.validate(validExtensionConfiguration)); + } + + @Test + public void testInvalidJsonDoc() { + ExtensionConfiguration invalidExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + "testExt", true, invalidJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + assertEquals(false, extensionsConfigurationDao.validate(invalidExtensionConfiguration)); + } + + @Test + public void testValidXmlDoc() { + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + "testExt", true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + assertEquals(true, extensionsConfigurationDao.validate(validExtensionConfiguration)); + } + + @Test + public void testInvalidXmlDoc() { + ExtensionConfiguration invalidExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + "testExt", true, invalidXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + assertEquals(false, extensionsConfigurationDao.validate(invalidExtensionConfiguration)); + } + + @Test + public void testStoreAndRetrieveConfigurationByNameJson() throws ConfigurationException { + String extName = "testExt"; + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + extName, true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + extensionsConfigurationDao.deleteConfigurationByName(extName); + } + + @Test + public void testStoreAndRetrieveConfigurationBySidJson() throws ConfigurationException { + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(sid, + "testExt", true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + extensionsConfigurationDao.deleteConfigurationBySid(sid); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationByNameJson() throws ConfigurationException { + String extName = "testExt"; + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + extName, true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + validExtensionConfiguration.setConfigurationData(updatedJsonObject, ExtensionConfiguration.configurationType.JSON); + extensionsConfigurationDao.updateConfiguration(validExtensionConfiguration); + retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertEquals(updatedJsonObject, retrievedConf.getConfigurationData()); + extensionsConfigurationDao.deleteConfigurationByName(extName); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationBySidJson() throws ConfigurationException { + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(sid, + "testExt", true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + validExtensionConfiguration.setConfigurationData(updatedJsonObject, ExtensionConfiguration.configurationType.JSON); + extensionsConfigurationDao.updateConfiguration(validExtensionConfiguration); + retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertEquals(updatedJsonObject, retrievedConf.getConfigurationData()); + extensionsConfigurationDao.deleteConfigurationBySid(sid); + } + + @Test + public void testStoreAndRetrieveConfigurationByNameXml() throws ConfigurationException { + String extName = "testExt"; + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + extName, true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + extensionsConfigurationDao.deleteConfigurationByName(extName); + } + + @Test + public void testStoreAndRetrieveConfigurationBySidXml() throws ConfigurationException { + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(sid, + "testExt", true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + extensionsConfigurationDao.deleteConfigurationBySid(sid); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationByNameXml() throws ConfigurationException { + String extName = "testExt"; + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + extName, true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + validExtensionConfiguration.setConfigurationData(updatedXmlDoc, ExtensionConfiguration.configurationType.XML); + extensionsConfigurationDao.updateConfiguration(validExtensionConfiguration); + retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertEquals(updatedXmlDoc, retrievedConf.getConfigurationData()); + extensionsConfigurationDao.deleteConfigurationByName(extName); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationBySidXml() throws ConfigurationException { + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration validExtensionConfiguration = new ExtensionConfiguration(sid, + "testExt", true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + extensionsConfigurationDao.addConfiguration(validExtensionConfiguration); + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), validExtensionConfiguration.getConfigurationData().toString()); + validExtensionConfiguration.setConfigurationData(updatedXmlDoc, ExtensionConfiguration.configurationType.XML); + extensionsConfigurationDao.updateConfiguration(validExtensionConfiguration); + retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertEquals(updatedXmlDoc, retrievedConf.getConfigurationData()); + extensionsConfigurationDao.deleteConfigurationBySid(sid); + } + + @Test + public void testStoreAndGetAllConfiguration() throws ConfigurationException { + Sid sid1 = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + Sid sid2 = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration validExtensionConfigurationXml = new ExtensionConfiguration(sid1, + "testExtXml", true, validXmlDoc, ExtensionConfiguration.configurationType.XML, DateTime.now()); + ExtensionConfiguration validExtensionConfigurationJson = new ExtensionConfiguration(sid2, + "testExtJson", true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + + extensionsConfigurationDao.addConfiguration(validExtensionConfigurationXml); + extensionsConfigurationDao.addConfiguration(validExtensionConfigurationJson); + + List confs = extensionsConfigurationDao.getAllConfiguration(); + + assertEquals(2, confs.size()); + + extensionsConfigurationDao.deleteConfigurationBySid(sid1); + extensionsConfigurationDao.deleteConfigurationBySid(sid2); + + confs = extensionsConfigurationDao.getAllConfiguration(); + assertEquals(0, confs.size()); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationByNameCheckVersionJson() throws ConfigurationException { + String extName = "testExt"; + ExtensionConfiguration originalExtensionConfiguration = new ExtensionConfiguration(Sid.generate(Sid.Type.EXTENSION_CONFIGURATION), + extName, true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(originalExtensionConfiguration); + + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationByName(extName); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), originalExtensionConfiguration.getConfigurationData().toString()); + + DateTime originalDateUpdated = retrievedConf.getDateUpdated(); + + boolean isUpdated = extensionsConfigurationDao.isLatestVersionByName(extName, originalDateUpdated); + assertEquals(isUpdated , false); + + originalExtensionConfiguration.setConfigurationData(updatedJsonObject, ExtensionConfiguration.configurationType.JSON); + extensionsConfigurationDao.updateConfiguration(originalExtensionConfiguration); + + isUpdated = extensionsConfigurationDao.isLatestVersionByName(extName, originalDateUpdated); + assertEquals(isUpdated , true); + + extensionsConfigurationDao.deleteConfigurationByName(extName); + } + + @Test + public void testStoreUpdateAndRetrieveConfigurationBySidCheckVersionJson() throws ConfigurationException { + String extName = "testExt"; + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + ExtensionConfiguration originalExtensionConfiguration = new ExtensionConfiguration(sid, + extName, true, validJsonObject, ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionsConfigurationDao.addConfiguration(originalExtensionConfiguration); + + ExtensionConfiguration retrievedConf = extensionsConfigurationDao.getConfigurationBySid(sid); + assertNotNull(retrievedConf); + assertEquals(retrievedConf.getConfigurationData().toString(), originalExtensionConfiguration.getConfigurationData().toString()); + + DateTime originalDateUpdated = retrievedConf.getDateUpdated(); + + boolean isUpdated = extensionsConfigurationDao.isLatestVersionBySid(sid, originalDateUpdated); + assertEquals(isUpdated , false); + + originalExtensionConfiguration.setConfigurationData(updatedJsonObject, ExtensionConfiguration.configurationType.JSON); + extensionsConfigurationDao.updateConfiguration(originalExtensionConfiguration); + + isUpdated = extensionsConfigurationDao.isLatestVersionBySid(sid, originalDateUpdated); + assertEquals(isUpdated , true); + + extensionsConfigurationDao.deleteConfigurationBySid(sid); + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/GatewaysDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GatewaysDaoTest.java similarity index 95% rename from restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/GatewaysDaoTest.java rename to restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GatewaysDaoTest.java index 4f053e5b39..78f2ea84c8 100644 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/GatewaysDaoTest.java +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GatewaysDaoTest.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import java.io.InputStream; import java.net.URI; @@ -30,9 +30,9 @@ import org.junit.Before; import org.junit.Test; -import org.mobicents.servlet.restcomm.dao.GatewaysDao; -import org.mobicents.servlet.restcomm.entities.Gateway; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.GatewaysDao; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GeolocationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GeolocationsDaoTest.java new file mode 100644 index 0000000000..fdb30ab3ba --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/GeolocationsDaoTest.java @@ -0,0 +1,257 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.dao.mybatis; + +import java.io.InputStream; +import java.net.URI; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import static org.junit.Assert.*; +import org.junit.Test; + +import org.restcomm.connect.dao.GeolocationDao; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.dao.entities.Geolocation.GeolocationType; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author Fernando Mendioroz + * + */ +public class GeolocationsDaoTest { + + private static MybatisDaoManager manager; + + public GeolocationsDaoTest() { + super(); + } + + @Before + public void before() { + final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void geolocationCreateReadUpdateDelete() { + + final Sid sid = Sid.generate(Sid.Type.GEOLOCATION); + final Sid accountSid = Sid.generate(Sid.Type.ACCOUNT); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/geolocation-hello-world.xml"); + final Geolocation.Builder builder = Geolocation.builder(); + builder.setSid(sid); + DateTime currentDateTime = DateTime.now(); + builder.setDateUpdated(currentDateTime); + builder.setAccountSid(accountSid); + builder.setSource("mlpclient1"); + builder.setDeviceIdentifier("device1"); + builder.setGeolocationType(GeolocationType.Immediate); + builder.setResponseStatus("successfull"); + builder.setCause("NA"); + builder.setCellId("12345"); + builder.setLocationAreaCode("978"); + builder.setMobileCountryCode(748); + builder.setMobileNetworkCode("03"); + builder.setNetworkEntityAddress((long) 59848779); + builder.setAgeOfLocationInfo(0); + builder.setDeviceLatitude("105.638643"); + builder.setDeviceLongitude("172.4394389"); + builder.setAccuracy((long) 7845); + builder.setInternetAddress("2001:0:9d38:6ab8:30a5:1c9d:58c6:5898"); + builder.setPhysicalAddress("D8-97-BA-19-02-D8"); + builder.setFormattedAddress("Avenida Brasil 2681, 11500, Montevideo, Uruguay"); + builder.setLocationTimestamp(currentDateTime); + builder.setEventGeofenceLatitude("-33.426280"); + builder.setEventGeofenceLongitude("-70.566560"); + builder.setRadius((long) 1500); + builder.setGeolocationPositioningType("Network"); + builder.setLastGeolocationResponse("true"); + builder.setApiVersion("2012-04-24"); + builder.setUri(url); + Geolocation geolocation = builder.build(); + final GeolocationDao geolocations = manager.getGeolocationDao(); + + // Create a new Geolocation in the data store. + geolocations.addGeolocation(geolocation); + + // Read the Geolocation from the data store. + Geolocation result = geolocations.getGeolocation(sid); + + // Validate the results. + assertTrue(result.getSid().equals(geolocation.getSid())); + assertTrue(result.getAccountSid().equals(geolocation.getAccountSid())); + assertTrue(result.getDateUpdated().equals(geolocation.getDateUpdated())); + assertTrue(result.getSource().equals(geolocation.getSource())); + assertTrue(result.getDeviceIdentifier().equals(geolocation.getDeviceIdentifier())); + assertTrue(result.getGeolocationType().equals(geolocation.getGeolocationType())); + assertTrue(result.getResponseStatus().equals(geolocation.getResponseStatus())); + assertTrue(result.getCause() == geolocation.getCause()); + assertTrue(result.getCellId().equals(geolocation.getCellId())); + assertTrue(result.getLocationAreaCode().equals(geolocation.getLocationAreaCode())); + assertTrue(result.getMobileCountryCode().equals(geolocation.getMobileCountryCode())); + assertTrue(result.getMobileNetworkCode().equals(geolocation.getMobileNetworkCode())); + assertTrue(result.getNetworkEntityAddress().equals(geolocation.getNetworkEntityAddress())); + assertTrue(result.getAgeOfLocationInfo().equals(geolocation.getAgeOfLocationInfo())); + assertTrue(result.getDeviceLatitude().equals(geolocation.getDeviceLatitude())); + assertTrue(result.getDeviceLongitude().equals(geolocation.getDeviceLongitude())); + assertTrue(result.getAccuracy().equals(geolocation.getAccuracy())); + assertTrue(result.getInternetAddress().equals(geolocation.getInternetAddress())); + assertTrue(result.getPhysicalAddress().equals(geolocation.getPhysicalAddress())); + assertTrue(result.getFormattedAddress().equals(geolocation.getFormattedAddress())); + assertTrue(result.getLocationTimestamp().equals(geolocation.getLocationTimestamp())); + assertTrue(result.getEventGeofenceLatitude().equals(geolocation.getEventGeofenceLatitude())); + assertTrue(result.getEventGeofenceLongitude().equals(geolocation.getEventGeofenceLongitude())); + assertTrue(result.getRadius() == geolocation.getRadius()); + assertTrue(result.getGeolocationPositioningType().equals(geolocation.getGeolocationPositioningType())); + assertTrue(result.getLastGeolocationResponse().equals(geolocation.getLastGeolocationResponse())); + assertTrue(result.getApiVersion().equals(geolocation.getApiVersion())); + assertTrue(result.getUri().equals(geolocation.getUri())); + + // Update the Geolocation + // deviceIdentifier, statusCallback and geolocationType can not be updated once created + URI url2 = URI.create("http://127.0.0.1:8080/restcomm/demos/geolocation-hello.xml"); + geolocation = geolocation.setDateUpdated(currentDateTime); + geolocation = geolocation.setSource("ble001"); + geolocation = geolocation.setResponseStatus("failed"); + geolocation = geolocation.setCause("API not compliant"); + geolocation = geolocation.setCellId("00010"); + geolocation = geolocation.setLocationAreaCode("0A1"); + geolocation = geolocation.setMobileCountryCode(1); + geolocation = geolocation.setMobileNetworkCode("33"); + geolocation = geolocation.setAgeOfLocationInfo(1); + geolocation = geolocation.setDeviceLatitude("-1.638643"); + geolocation = geolocation.setDeviceLongitude("-172.4394389"); + geolocation = geolocation.setAccuracy((long) 9876352); + geolocation = geolocation.setInternetAddress("200.0.91.253"); + geolocation = geolocation.setPhysicalAddress("A1-DD-0A-27-92-00"); + geolocation = geolocation.setFormattedAddress("27NW Street, 23456, Greenwich, Ireland"); + geolocation = geolocation.setLocationTimestamp(currentDateTime); + geolocation = geolocation.setEventGeofenceLatitude("33.426280"); + geolocation = geolocation.setEventGeofenceLongitude("70.426280"); + geolocation = geolocation.setRadius((long) 99999); + geolocation = geolocation.setGeolocationPositioningType("GPS"); + geolocation = geolocation.setLastGeolocationResponse("false"); + geolocation = geolocation.setUri(url2); + + // Update the Geolocation in the data store g + geolocations.updateGeolocation(geolocation); + + // Read the updated Geolocation from the data store + result = geolocations.getGeolocation(sid); + + // Validate the results + assertTrue(result.getDateUpdated().equals(geolocation.getDateUpdated())); + assertTrue(result.getAccountSid().equals(geolocation.getAccountSid())); + assertTrue(result.getSource().equals(geolocation.getSource())); + assertTrue(result.getResponseStatus().equals(geolocation.getResponseStatus())); + assertTrue(result.getCause() == geolocation.getCause()); + assertTrue(result.getCellId().equals(geolocation.getCellId())); + assertTrue(result.getLocationAreaCode().equals(geolocation.getLocationAreaCode())); + assertTrue(result.getMobileCountryCode().equals(geolocation.getMobileCountryCode())); + assertTrue(result.getMobileNetworkCode().equals(geolocation.getMobileNetworkCode())); + assertTrue(result.getNetworkEntityAddress().equals(geolocation.getNetworkEntityAddress())); + assertTrue(result.getAgeOfLocationInfo().equals(geolocation.getAgeOfLocationInfo())); + assertTrue(result.getDeviceLatitude().equals(geolocation.getDeviceLatitude())); + assertTrue(result.getDeviceLongitude().equals(geolocation.getDeviceLongitude())); + assertTrue(result.getAccuracy().equals(geolocation.getAccuracy())); + assertTrue(result.getInternetAddress().equals(geolocation.getInternetAddress())); + assertTrue(result.getPhysicalAddress().equals(geolocation.getPhysicalAddress())); + assertTrue(result.getFormattedAddress().equals(geolocation.getFormattedAddress())); + assertTrue(result.getLocationTimestamp().equals(geolocation.getLocationTimestamp())); + assertTrue(result.getEventGeofenceLatitude().equals(geolocation.getEventGeofenceLatitude())); + assertTrue(result.getEventGeofenceLongitude().equals(geolocation.getEventGeofenceLongitude())); + assertTrue(result.getRadius().equals(geolocation.getRadius())); + assertTrue(result.getGeolocationPositioningType().equals(geolocation.getGeolocationPositioningType())); + assertTrue(result.getLastGeolocationResponse().equals(geolocation.getLastGeolocationResponse())); + + // Delete the Geolocation record + geolocations.removeGeolocation(sid); + + // Validate the Geolocation record was removed. + assertTrue(geolocations.getGeolocation(sid) == null); + } + + @Test + public void geolocationReadDeleteByAccountSid() { + + final Sid sid = Sid.generate(Sid.Type.GEOLOCATION); + final Sid accountSid = Sid.generate(Sid.Type.ACCOUNT); + URI url = URI.create("geolocation-hello-world.xml"); + final Geolocation.Builder builder = Geolocation.builder(); + builder.setSid(sid); + DateTime currentDateTime = DateTime.now(); + builder.setDateUpdated(currentDateTime); + builder.setAccountSid(accountSid); + builder.setSource("mlpClient1"); + builder.setDeviceIdentifier("59899770937"); + builder.setGeolocationType(GeolocationType.Immediate); + builder.setResponseStatus("successfull"); + builder.setCause("NA"); + builder.setCellId("12345"); + builder.setLocationAreaCode("978"); + builder.setMobileCountryCode(748); + builder.setMobileNetworkCode("03"); + builder.setNetworkEntityAddress((long) 59848779); + builder.setAgeOfLocationInfo(0); + builder.setDeviceLatitude("105.638643"); + builder.setDeviceLongitude("172.4394389"); + builder.setAccuracy((long) 7845); + builder.setInternetAddress("2001:0:9d38:6ab8:30a5:1c9d:58c6:5898"); + builder.setPhysicalAddress("D8-97-BA-19-02-D8"); + builder.setFormattedAddress("Avenida Brasil 2681, 11500, Montevideo, Uruguay"); + builder.setLocationTimestamp(currentDateTime); + builder.setEventGeofenceLatitude("-33.426280"); + builder.setEventGeofenceLongitude("-70.566560"); + builder.setRadius((long) 1500); + builder.setGeolocationPositioningType("Network"); + builder.setLastGeolocationResponse("true"); + builder.setApiVersion("2012-04-24"); + builder.setUri(url); + final Geolocation geolocation = builder.build(); + final GeolocationDao geolocations = manager.getGeolocationDao(); + + // Create a new Geolocation in the data store. + geolocations.addGeolocation(geolocation); + + // Get all the Geolocations for a specific account. + assertTrue(geolocations.getGeolocations(accountSid) != null); + + // Remove the Geolocations for a specific account. + geolocations.removeGeolocation(accountSid); + + // Validate that the Geolocation were removed. + assertTrue(geolocations.getGeolocation(accountSid) == null); + } + +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/IncomingPhoneNumbersDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/IncomingPhoneNumbersDaoTest.java new file mode 100644 index 0000000000..a1825cfdb6 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/IncomingPhoneNumbersDaoTest.java @@ -0,0 +1,433 @@ +/* + * 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.dao.mybatis; + +import java.io.InputStream; +import java.net.URI; +import java.util.List; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; + +import org.junit.After; +import static org.junit.Assert.*; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.SearchFilterMode; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public class IncomingPhoneNumbersDaoTest { + private static MybatisDaoManager manager; + + public IncomingPhoneNumbersDaoTest() { + super(); + } + + @Before + public void before() { + final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void createReadUpdateDelete() { + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account = Sid.generate(Sid.Type.ACCOUNT); + Sid application = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + String method = "GET"; + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + builder.setSid(sid); + builder.setFriendlyName("Incoming Phone Number Test"); + builder.setAccountSid(account); + builder.setPhoneNumber("+12223334444"); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setVoiceUrl(url); + builder.setCost("0.50"); + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(url); + builder.setVoiceFallbackMethod(method); + builder.setStatusCallback(url); + builder.setStatusCallbackMethod(method); + builder.setVoiceApplicationSid(application); + builder.setSmsUrl(url); + builder.setSmsMethod(method); + builder.setSmsFallbackUrl(url); + builder.setSmsFallbackMethod(method); + builder.setSmsApplicationSid(application); + builder.setUri(url); + builder.setOrganizationSid(Sid.generate(Sid.Type.ORGANIZATION)); + IncomingPhoneNumber number = builder.build(); + final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); + // Create a new incoming phone number in the data store. + numbers.addIncomingPhoneNumber(number); + // Read the incoming phone number from the data store. + IncomingPhoneNumber result = numbers.getIncomingPhoneNumber(sid); + // Validate the results. + assertTrue(result.getSid().equals(number.getSid())); + assertTrue(result.getFriendlyName().equals(number.getFriendlyName())); + assertTrue(result.getAccountSid().equals(number.getAccountSid())); + assertTrue(result.getPhoneNumber().equals(number.getPhoneNumber())); + assertTrue(result.getApiVersion().equals(number.getApiVersion())); + assertFalse(result.hasVoiceCallerIdLookup()); + assertTrue(result.getVoiceUrl().equals(number.getVoiceUrl())); + assertTrue(result.getVoiceMethod().equals(number.getVoiceMethod())); + assertTrue(result.getVoiceFallbackUrl().equals(number.getVoiceFallbackUrl())); + assertTrue(result.getVoiceFallbackMethod().equals(number.getVoiceFallbackMethod())); + assertTrue(result.getStatusCallback().equals(number.getStatusCallback())); + assertTrue(result.getStatusCallbackMethod().equals(number.getStatusCallbackMethod())); + assertTrue(result.getVoiceApplicationSid().equals(number.getVoiceApplicationSid())); + assertTrue(result.getSmsUrl().equals(number.getSmsUrl())); + assertTrue(result.getSmsMethod().equals(number.getSmsMethod())); + assertTrue(result.getSmsFallbackUrl().equals(number.getSmsFallbackUrl())); + assertTrue(result.getSmsFallbackMethod().equals(number.getSmsFallbackMethod())); + assertTrue(result.getSmsApplicationSid().equals(number.getSmsApplicationSid())); + assertTrue(result.getUri().equals(number.getUri())); + // Update the incoming phone number. + application = Sid.generate(Sid.Type.APPLICATION); + url = URI.create("http://127.0.0.1:8080/restcomm/demos/world-hello.xml"); + method = "POST"; + number.setFriendlyName("Test Application"); + number.setHasVoiceCallerIdLookup(true); + number.setVoiceUrl(url); + number.setVoiceMethod(method); + number.setVoiceFallbackUrl(url); + number.setVoiceFallbackMethod(method); + number.setStatusCallback(url); + number.setStatusCallbackMethod(method); + number.setVoiceApplicationSid(application); + number.setSmsUrl(url); + number.setCost("0.50"); + number.setSmsMethod(method); + number.setSmsFallbackUrl(url); + number.setSmsFallbackMethod(method); + number.setSmsApplicationSid(application); + Sid newOrganizationSid = Sid.generate(Sid.Type.ORGANIZATION); + number.setOrganizationSid(newOrganizationSid); + numbers.updateIncomingPhoneNumber(number); + // Read the updated application from the data store. + result = numbers.getIncomingPhoneNumber(sid); + // Validate the results. + assertTrue(result.getSid().equals(number.getSid())); + assertTrue(result.getFriendlyName().equals(number.getFriendlyName())); + assertTrue(result.getAccountSid().equals(number.getAccountSid())); + assertTrue(result.getPhoneNumber().equals(number.getPhoneNumber())); + assertTrue(result.getApiVersion().equals(number.getApiVersion())); + assertTrue(result.hasVoiceCallerIdLookup()); + assertTrue(result.getVoiceUrl().equals(number.getVoiceUrl())); + assertTrue(result.getVoiceMethod().equals(number.getVoiceMethod())); + assertTrue(result.getVoiceFallbackUrl().equals(number.getVoiceFallbackUrl())); + assertTrue(result.getVoiceFallbackMethod().equals(number.getVoiceFallbackMethod())); + assertTrue(result.getStatusCallback().equals(number.getStatusCallback())); + assertTrue(result.getStatusCallbackMethod().equals(number.getStatusCallbackMethod())); + assertTrue(result.getVoiceApplicationSid().equals(number.getVoiceApplicationSid())); + assertTrue(result.getSmsUrl().equals(number.getSmsUrl())); + assertTrue(result.getSmsMethod().equals(number.getSmsMethod())); + assertTrue(result.getSmsFallbackUrl().equals(number.getSmsFallbackUrl())); + assertTrue(result.getSmsFallbackMethod().equals(number.getSmsFallbackMethod())); + assertTrue(result.getSmsApplicationSid().equals(number.getSmsApplicationSid())); + assertTrue(result.getUri().equals(number.getUri())); + assertEquals(newOrganizationSid.toString(), result.getOrganizationSid().toString()); + // Delete the incoming phone number. + numbers.removeIncomingPhoneNumber(sid); + // Validate that the incoming phone number was removed. + assertNull(numbers.getIncomingPhoneNumber(sid)); + } + + @Test + public void applicationFriendlyNameReturned() { + final IncomingPhoneNumbersDao dao = manager.getIncomingPhoneNumbersDao(); + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byAccountSid("ACae6e420f425248d6a26948c17a9e2acf"); + filterBuilder.sortedBy("phone_number", "ASC"); + filterBuilder.limited(50, 0); + List phoneNumbers = dao.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + Assert.assertEquals("Only a single phone number expected",1, phoneNumbers.size()); + IncomingPhoneNumber number = phoneNumbers.get(0); + Assert.assertEquals("app0", number.getVoiceApplicationName()); + Assert.assertEquals("app1", number.getSmsApplicationName()); + Assert.assertEquals("app2", number.getUssdApplicationName()); + } + + @Test + public void getByPhoneNumber() { + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account = Sid.generate(Sid.Type.ACCOUNT); + Sid application = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + String method = "GET"; + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + builder.setSid(sid); + builder.setFriendlyName("Incoming Phone Number Test"); + builder.setAccountSid(account); + builder.setPhoneNumber("+12223334444"); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setVoiceUrl(url); + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(url); + builder.setVoiceFallbackMethod(method); + builder.setStatusCallback(url); + builder.setStatusCallbackMethod(method); + builder.setVoiceApplicationSid(application); + builder.setSmsUrl(url); + builder.setSmsMethod(method); + builder.setSmsFallbackUrl(url); + builder.setSmsFallbackMethod(method); + builder.setSmsApplicationSid(application); + builder.setUri(url); + builder.setOrganizationSid(Sid.generate(Sid.Type.ORGANIZATION)); + IncomingPhoneNumber number = builder.build(); + final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); + // Create a new incoming phone number in the data store. + numbers.addIncomingPhoneNumber(number); + // Read the incoming phone number from the data store. + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byPhoneNumber("+12223334444"); + filterBuilder.byAccountSid(account.toString()); + List incomingPhoneNumbers = numbers.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + assertNotNull (incomingPhoneNumbers); + assertEquals (1, incomingPhoneNumbers.size()); + IncomingPhoneNumber result = incomingPhoneNumbers.get(0); + assertEquals(number.getSid(), result.getSid()); + + //use wildcard mode now + filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byPhoneNumber("2223334444"); + filterBuilder.byAccountSid(account.toString()); + filterBuilder.usingMode(SearchFilterMode.WILDCARD_MATCH); + incomingPhoneNumbers = numbers.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + assertNotNull (incomingPhoneNumbers); + assertEquals (1, incomingPhoneNumbers.size()); + + // Delete the incoming phone number. + numbers.removeIncomingPhoneNumber(sid); + // Validate that the incoming phone number was removed. + assertNull(numbers.getIncomingPhoneNumber(sid) ); + } + + @Test + public void getByPhoneNumberUAndOrg() { + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account = Sid.generate(Sid.Type.ACCOUNT); + Sid org1 = Sid.generate(Sid.Type.ORGANIZATION); + final Sid sid2 = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account2 = Sid.generate(Sid.Type.ACCOUNT); + Sid org2 = Sid.generate(Sid.Type.ORGANIZATION); + + Sid application = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + String method = "GET"; + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + builder.setSid(sid); + builder.setFriendlyName("Incoming Phone Number Test"); + builder.setAccountSid(account); + builder.setPhoneNumber("+12223334444"); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setVoiceUrl(url); + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(url); + builder.setVoiceFallbackMethod(method); + builder.setStatusCallback(url); + builder.setStatusCallbackMethod(method); + builder.setVoiceApplicationSid(application); + builder.setSmsUrl(url); + builder.setSmsMethod(method); + builder.setSmsFallbackUrl(url); + builder.setSmsFallbackMethod(method); + builder.setSmsApplicationSid(application); + builder.setUri(url); + builder.setOrganizationSid(org1); + builder.setPureSip(Boolean.FALSE); + IncomingPhoneNumber number = builder.build(); + final IncomingPhoneNumber.Builder builder2 = IncomingPhoneNumber.builder(); + builder2.setSid(sid2); + builder2.setFriendlyName("Incoming Phone Number Test"); + builder2.setAccountSid(account2); + builder2.setPhoneNumber("+12223334444"); + builder2.setApiVersion("2012-04-24"); + builder2.setHasVoiceCallerIdLookup(false); + builder2.setVoiceUrl(url); + builder2.setVoiceMethod(method); + builder2.setVoiceFallbackUrl(url); + builder2.setVoiceFallbackMethod(method); + builder2.setStatusCallback(url); + builder2.setStatusCallbackMethod(method); + builder2.setVoiceApplicationSid(application); + builder2.setSmsUrl(url); + builder2.setSmsMethod(method); + builder2.setSmsFallbackUrl(url); + builder2.setSmsFallbackMethod(method); + builder2.setSmsApplicationSid(application); + builder2.setUri(url); + builder2.setOrganizationSid(org2); + builder2.setPureSip(Boolean.FALSE); + + IncomingPhoneNumber number2 = builder2.build(); + final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); + // Create a new incoming phone number in the data store. + numbers.addIncomingPhoneNumber(number2); + numbers.addIncomingPhoneNumber(number); + + + // Read the incoming phone number from the data store. + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byPhoneNumber("+12223334444"); + filterBuilder.byOrgSid(org2.toString()); + filterBuilder.byPureSIP(Boolean.FALSE); + IncomingPhoneNumberFilter numFilter = filterBuilder.build(); + List incomingPhoneNumbers = numbers.getIncomingPhoneNumbersByFilter(numFilter); + assertNotNull(incomingPhoneNumbers); + assertEquals(1, incomingPhoneNumbers.size()); + assertEquals(Integer.valueOf(1), numbers.getTotalIncomingPhoneNumbers(numFilter)); + } + + @Test + public void getRegexes() { + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account = Sid.generate(Sid.Type.ACCOUNT); + Sid org1 = Sid.generate(Sid.Type.ORGANIZATION); + final Sid sid2 = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account2 = Sid.generate(Sid.Type.ACCOUNT); + Sid org2 = Sid.generate(Sid.Type.ORGANIZATION); + + Sid application = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + String method = "GET"; + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + builder.setSid(sid); + builder.setFriendlyName("Incoming Phone Number Test"); + builder.setAccountSid(account); + builder.setPhoneNumber("+12.*"); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setVoiceUrl(url); + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(url); + builder.setVoiceFallbackMethod(method); + builder.setStatusCallback(url); + builder.setStatusCallbackMethod(method); + builder.setVoiceApplicationSid(application); + builder.setSmsUrl(url); + builder.setSmsMethod(method); + builder.setSmsFallbackUrl(url); + builder.setSmsFallbackMethod(method); + builder.setSmsApplicationSid(application); + builder.setUri(url); + builder.setOrganizationSid(org1); + builder.setPureSip(Boolean.TRUE); + IncomingPhoneNumber number = builder.build(); + final IncomingPhoneNumber.Builder builder2 = IncomingPhoneNumber.builder(); + builder2.setSid(sid2); + builder2.setFriendlyName("Incoming Phone Number Test"); + builder2.setAccountSid(account2); + builder2.setPhoneNumber("+12223334444"); + builder2.setApiVersion("2012-04-24"); + builder2.setHasVoiceCallerIdLookup(false); + builder2.setVoiceUrl(url); + builder2.setVoiceMethod(method); + builder2.setVoiceFallbackUrl(url); + builder2.setVoiceFallbackMethod(method); + builder2.setStatusCallback(url); + builder2.setStatusCallbackMethod(method); + builder2.setVoiceApplicationSid(application); + builder2.setSmsUrl(url); + builder2.setSmsMethod(method); + builder2.setSmsFallbackUrl(url); + builder2.setSmsFallbackMethod(method); + builder2.setSmsApplicationSid(application); + builder2.setUri(url); + builder2.setOrganizationSid(org2); + builder2.setPureSip(Boolean.FALSE); + + IncomingPhoneNumber number2 = builder2.build(); + final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); + // Create a new incoming phone number in the data store. + numbers.addIncomingPhoneNumber(number2); + numbers.addIncomingPhoneNumber(number); + + + // Read the incoming phone number from the data store. + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byOrgSid(org1.toString()); + filterBuilder.byPureSIP(Boolean.TRUE); + IncomingPhoneNumberFilter numFilter = filterBuilder.build(); + List incomingPhoneNumbers = numbers.getIncomingPhoneNumbersRegex(numFilter); + assertNotNull(incomingPhoneNumbers); + assertEquals(1, incomingPhoneNumbers.size()); + } + + @Test + public void removeByAccountSid() { + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + Sid account = Sid.generate(Sid.Type.ACCOUNT); + Sid application = Sid.generate(Sid.Type.APPLICATION); + URI url = URI.create("http://127.0.0.1:8080/restcomm/demos/hello-world.xml"); + String method = "GET"; + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + builder.setSid(sid); + builder.setFriendlyName("Incoming Phone Number Test"); + builder.setAccountSid(account); + builder.setPhoneNumber("+12223334444"); + builder.setApiVersion("2012-04-24"); + builder.setHasVoiceCallerIdLookup(false); + builder.setVoiceUrl(url); + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(url); + builder.setVoiceFallbackMethod(method); + builder.setStatusCallback(url); + builder.setStatusCallbackMethod(method); + builder.setVoiceApplicationSid(application); + builder.setSmsUrl(url); + builder.setSmsMethod(method); + builder.setSmsFallbackUrl(url); + builder.setSmsFallbackMethod(method); + builder.setSmsApplicationSid(application); + builder.setUri(url); + builder.setOrganizationSid(Sid.generate(Sid.Type.ORGANIZATION)); + IncomingPhoneNumber number = builder.build(); + final IncomingPhoneNumbersDao numbers = manager.getIncomingPhoneNumbersDao(); + // Create a new incoming phone number in the data store. + numbers.addIncomingPhoneNumber(number); + assertEquals(1, numbers.getIncomingPhoneNumbers(account).size()); + // Delete the incoming phone number. + numbers.removeIncomingPhoneNumbers(account); + assertTrue(numbers.getIncomingPhoneNumbers(account).isEmpty()); + } +} \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/NotificationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/NotificationsDaoTest.java similarity index 92% rename from restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/NotificationsDaoTest.java rename to restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/NotificationsDaoTest.java index 02b9611c14..19104a0d08 100644 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/NotificationsDaoTest.java +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/NotificationsDaoTest.java @@ -17,22 +17,25 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import static org.junit.Assert.*; import java.io.InputStream; import java.net.URI; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -40,6 +43,8 @@ public final class NotificationsDaoTest { private static MybatisDaoManager manager; + protected static Sid instanceId = Sid.generate(Sid.Type.INSTANCE); + public NotificationsDaoTest() { super(); } @@ -51,6 +56,17 @@ public void before() { final SqlSessionFactory factory = builder.build(data); manager = new MybatisDaoManager(); manager.start(factory); + + XMLConfiguration xmlConfiguration = new XMLConfiguration(); + xmlConfiguration.setDelimiterParsingDisabled(true); + xmlConfiguration.setAttributeSplittingDisabled(true); + try { + xmlConfiguration.load("restcomm.xml"); + RestcommConfiguration.createOnce(xmlConfiguration); + RestcommConfiguration.getInstance().getMain().setInstanceId(instanceId.toString()); + } catch (ConfigurationException e) { + e.printStackTrace(); + } } @After diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/OrganizationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/OrganizationsDaoTest.java new file mode 100644 index 0000000000..a5f08b7def --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/OrganizationsDaoTest.java @@ -0,0 +1,100 @@ +/* + * 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.dao.mybatis; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URISyntaxException; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.joda.time.DateTime; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.entities.Organization; + +import junit.framework.Assert; + +public class OrganizationsDaoTest extends DaoTest { + private static MybatisDaoManager manager; + + public OrganizationsDaoTest() { + super(); + } + + @Before + public void before() throws Exception { + sandboxRoot = createTempDir("organizationsTest"); + String mybatisFilesPath = getClass().getResource("/organizationsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() throws Exception { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void addOrganizationsTest() throws IllegalArgumentException, URISyntaxException { + OrganizationsDao dao = manager.getOrganizationsDao(); + Sid sid = Sid.generate(Sid.Type.ORGANIZATION); + dao.addOrganization(new Organization(sid, "test.restcomm.com", new DateTime(), new DateTime(), Organization.Status.ACTIVE)); + Organization organization = dao.getOrganization(sid); + Assert.assertNotNull("Organization not found",organization); + Assert.assertNotNull(organization.getSid()); + } + + @Test + public void addOrganizationsTestWithDot() throws IllegalArgumentException, URISyntaxException { + OrganizationsDao dao = manager.getOrganizationsDao(); + Sid sid = Sid.generate(Sid.Type.ORGANIZATION); + dao.addOrganization(new Organization(sid, "test.restcomm.com.", new DateTime(), new DateTime(), Organization.Status.ACTIVE)); + Organization organization = dao.getOrganization(sid); + Assert.assertEquals("test.restcomm.com",organization.getDomainName()); + } + + @Test + public void readOrganization() { + OrganizationsDao dao = manager.getOrganizationsDao(); + Organization organization = dao.getOrganization(new Sid("ORafbe225ad37541eba518a74248f0ac4d")); + Assert.assertNotNull("Organization not found",organization); + } + + @Test + public void readOrganizationByDomainDomain() { + OrganizationsDao dao = manager.getOrganizationsDao(); + Organization organization = dao.getOrganizationByDomainName("test2.restcomm.com"); + Assert.assertNotNull("Organization not found",organization); + organization = dao.getOrganizationByDomainName("test2.restcomm.com."); + Assert.assertNotNull("Organization not found",organization); + } + +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfileAssociationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfileAssociationsDaoTest.java new file mode 100644 index 0000000000..4d8fe8a697 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfileAssociationsDaoTest.java @@ -0,0 +1,143 @@ +package org.restcomm.connect.dao.mybatis; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.util.Calendar; +import java.util.List; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.entities.ProfileAssociation; + +import static org.junit.Assert.assertEquals; +import org.restcomm.connect.dao.ProfilesDao; +import org.restcomm.connect.dao.entities.Profile; + +public class ProfileAssociationsDaoTest extends DaoTest { + + private static MybatisDaoManager manager; + private static final String jsonProfile = "{}"; + + public ProfileAssociationsDaoTest() { + super(); + } + + @Before + public void before() throws Exception { + sandboxRoot = createTempDir("organizationsTest"); + String mybatisFilesPath = getClass().getResource("/organizationsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() throws Exception { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void profileAssociationsCRUDTest() throws IllegalArgumentException, URISyntaxException { + ProfileAssociationsDao dao = manager.getProfileAssociationsDao(); + //TODO: update profile sid type below after merge from master + Sid profileSid = Sid.generate(Sid.Type.ORGANIZATION); + Sid targetSid = Sid.generate(Sid.Type.ACCOUNT); + ProfileAssociation profileAssociation = new ProfileAssociation(profileSid, targetSid, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + //Add ProfileAssociation + dao.addProfileAssociation(profileAssociation); + + //Read ProfileAssociation ByTargetSid + ProfileAssociation resultantProfileAssociation = dao.getProfileAssociationByTargetSid(targetSid.toString()); + Assert.assertNotNull(resultantProfileAssociation); + Assert.assertEquals(profileAssociation.getProfileSid(), resultantProfileAssociation.getProfileSid()); + + //Read ProfileAssociation ByTargetSid + List resultantProfileAssociations = dao.getProfileAssociationsByProfileSid(profileSid.toString()); + Assert.assertNotNull(resultantProfileAssociations); + Assert.assertEquals(1, resultantProfileAssociations.size()); + Assert.assertEquals(profileAssociation.toString(), resultantProfileAssociations.get(0).toString()); + + // Add another ProfileAssociation with same profile + Sid targetSid2 = Sid.generate(Sid.Type.ACCOUNT); + ProfileAssociation profileAssociation2 = new ProfileAssociation(profileSid, targetSid2, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + dao.addProfileAssociation(profileAssociation2); + resultantProfileAssociations = dao.getProfileAssociationsByProfileSid(profileSid.toString()); + Assert.assertNotNull(resultantProfileAssociations); + Assert.assertEquals(2, resultantProfileAssociations.size()); + + //Update Associated Profile Of All Such ProfileSid + //TODO: update profile sid type below after merge from master + Sid newProfileSid = Sid.generate(Sid.Type.ORGANIZATION); + dao.updateAssociatedProfileOfAllSuchProfileSid(profileSid.toString(), newProfileSid.toString()); + Assert.assertEquals(0, dao.getProfileAssociationsByProfileSid(profileSid.toString()).size()); + Assert.assertEquals(2, dao.getProfileAssociationsByProfileSid(newProfileSid.toString()).size()); + + //Update ProfileAssociation of target + //TODO: update profile sid type below after merge from master + Sid newProfileSid2 = Sid.generate(Sid.Type.ORGANIZATION); + profileAssociation = dao.getProfileAssociationsByProfileSid(newProfileSid.toString()).get(0); + ProfileAssociation updatedProfileAssociation = profileAssociation.setProfileSid(newProfileSid2); + dao.updateProfileAssociationOfTargetSid(updatedProfileAssociation); + ProfileAssociation resultantProfileAssociationdao = dao.getProfileAssociationByTargetSid(updatedProfileAssociation.getTargetSid().toString()); + Assert.assertNotNull(resultantProfileAssociationdao); + Assert.assertEquals(updatedProfileAssociation.getProfileSid().toString(), resultantProfileAssociationdao.getProfileSid().toString()); + + //Delete ByTargetSid + int removed = dao.deleteProfileAssociationByTargetSid(resultantProfileAssociationdao.getTargetSid().toString(), + resultantProfileAssociationdao.getProfileSid().toString()); + assertEquals(1, removed); + ProfileAssociation profileAssociationByTargetSid = dao.getProfileAssociationByTargetSid(resultantProfileAssociationdao.getTargetSid().toString()); + Assert.assertNull(profileAssociationByTargetSid); + + //Delete ByProfileSid + dao.deleteProfileAssociationByProfileSid(newProfileSid2.toString()); + Assert.assertEquals(0, dao.getProfileAssociationsByProfileSid(newProfileSid2.toString()).size()); + + } + + + /** + * changep rofile for an account. + * + * Simlaute disorder of unlink7link in network + * @throws IllegalArgumentException + * @throws URISyntaxException + */ + @Test + public void changeProfile() throws IllegalArgumentException, URISyntaxException { + ProfileAssociationsDao dao = manager.getProfileAssociationsDao(); + ProfilesDao profileDao = manager.getProfilesDao(); + + Sid targetSid = Sid.generate(Sid.Type.ACCOUNT); + Profile profile = new Profile(Sid.generate(Sid.Type.PROFILE).toString(), jsonProfile, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + Profile profile2 = new Profile(Sid.generate(Sid.Type.PROFILE).toString(), jsonProfile, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + profileDao.addProfile(profile); + profileDao.addProfile(profile2); + ProfileAssociation profileAssociation = new ProfileAssociation(new Sid(profile.getSid()), targetSid, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + dao.addProfileAssociation(profileAssociation); + + + //linking to new profile comes before unlinking to previous + ProfileAssociation profileAssociation2 = new ProfileAssociation(new Sid(profile2.getSid()), targetSid, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + dao.deleteProfileAssociationByTargetSid(targetSid.toString()); + dao.addProfileAssociation(profileAssociation2); + + //unlinking to previous comes after + int removed = dao.deleteProfileAssociationByTargetSid(targetSid.toString(), profile.getSid()); + //the association was removed in last linking + assertEquals(0, removed); + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfilesDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfilesDaoTest.java new file mode 100644 index 0000000000..7c46912fe4 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/ProfilesDaoTest.java @@ -0,0 +1,106 @@ +/* + * 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.dao.mybatis; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.ProfilesDao; +import org.restcomm.connect.dao.entities.Profile; + +import junit.framework.Assert; + +public class ProfilesDaoTest extends DaoTest { + private static MybatisDaoManager manager; + private static final String jsonProfile = "{ \"FACEnablement\": { \"destinations\": { \"allowedPrefixes\": [\"US\", \"Canada\"] }, \"outboundPSTN\": { }, \"inboundPSTN\": { }, \"outboundSMS\": { }, \"inboundSMS\": { } }}"; + private static final String jsonUpdateProfile = "{ \"FACEnablement\": { \"destinations\": { \"allowedPrefixes\": [\"US\", \"Canada\", \"Pakitsan\"] }, \"outboundPSTN\": { }, \"inboundPSTN\": { }, \"outboundSMS\": { }, \"inboundSMS\": { } }}"; + + public ProfilesDaoTest() { + super(); + } + + @Before + public void before() throws Exception { + sandboxRoot = createTempDir("organizationsTest"); + String mybatisFilesPath = getClass().getResource("/organizationsDao").getFile(); + setupSandbox(mybatisFilesPath, sandboxRoot); + + String mybatisXmlPath = sandboxRoot.getPath() + "/mybatis_updated.xml"; + final InputStream data = new FileInputStream(mybatisXmlPath); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() throws Exception { + manager.shutdown(); + removeTempDir(sandboxRoot.getAbsolutePath()); + } + + @Test + public void ProfileCRUDTest() throws IllegalArgumentException, URISyntaxException, IOException, SQLException { + ProfilesDao dao = manager.getProfilesDao(); + Profile profile = new Profile(Sid.generate(Sid.Type.PROFILE).toString(), jsonProfile, Calendar.getInstance().getTime(), Calendar.getInstance().getTime()); + + // Add Profile + dao.addProfile(profile); + + // Read Profile + Profile resultantProfile = dao.getProfile(profile.getSid()); + Assert.assertNotNull(resultantProfile); + Assert.assertEquals(profile.getSid(), resultantProfile.getSid()); +// Assert.assertTrue(Arrays.equals(profile.getProfileDocument(), resultantProfile.getProfileDocument())); + + //Read Profile List + List profilelist = dao.getAllProfiles(); + Assert.assertNotNull(profilelist); + Assert.assertEquals(1, profilelist.size()); + + // Update Profile + Profile updatedProfile = profile.setProfileDocument(jsonUpdateProfile); + dao.updateProfile(updatedProfile); + + + resultantProfile = dao.getProfile(updatedProfile.getSid()); + Assert.assertNotNull(resultantProfile); + Assert.assertEquals(updatedProfile.getSid(), resultantProfile.getSid()); +// Assert.assertTrue(Arrays.equals(updatedProfile.getProfileDocument(), resultantProfile.getProfileDocument())); + + // Delete Profile + dao.deleteProfile(updatedProfile.getSid().toString()); + + resultantProfile = dao.getProfile(profile.getSid()); + Assert.assertNull(resultantProfile); + } +} diff --git a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/RegistrationsDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/RegistrationsDaoTest.java similarity index 83% rename from restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/RegistrationsDaoTest.java rename to restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/RegistrationsDaoTest.java index 1713994ffe..b82dad4cd1 100644 --- a/restcomm/restcomm.dao/src/test/java/org/mobicents/servlet/restcomm/dao/mybatis/RegistrationsDaoTest.java +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/RegistrationsDaoTest.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.dao.mybatis; +package org.restcomm.connect.dao.mybatis; import static org.junit.Assert.*; @@ -29,9 +29,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mobicents.servlet.restcomm.dao.RegistrationsDao; -import org.mobicents.servlet.restcomm.entities.Registration; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.dao.RegistrationsDao; +import org.restcomm.connect.dao.entities.Registration; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -60,18 +60,19 @@ public void after() { @Test public void createReadUpdateDelete() { final Sid sid = Sid.generate(Sid.Type.REGISTRATION); + final Sid orgSid = Sid.generate(Sid.Type.ORGANIZATION); final DateTime now = DateTime.now(); String username = "tom_" + now; String displayName = "Tom_" + now; - Registration registration = new Registration(sid, now, now, now, "sip:tom@company.com", displayName, username, - "TestUserAgent/1.0", 3600, "sip:tom@company.com"); + Registration registration = new Registration(sid, "instanceId", now, now, now, "sip:tom@company.com", displayName, username, + "TestUserAgent/1.0", 3600, "sip:tom@company.com", true, false, orgSid); final RegistrationsDao registrations = manager.getRegistrationsDao(); // Create a new registration in the data store. assertFalse(registrations.hasRegistration(registration)); registrations.addRegistration(registration); assertTrue(registrations.hasRegistration(registration)); // Read the registration from the data store. - Registration result = registrations.getRegistration(username); + Registration result = registrations.getRegistration(username, orgSid); // Validate the results. assertTrue(registrations.getRegistrations().size() >= 1); assertTrue(result.getSid().equals(registration.getSid())); @@ -84,11 +85,12 @@ public void createReadUpdateDelete() { assertTrue(result.getLocation().equals(registration.getLocation())); assertTrue(result.getUserAgent().equals(registration.getUserAgent())); assertTrue(result.getTimeToLive() == registration.getTimeToLive()); + assertTrue(result.isWebRTC()); // Update the registration. registration = registration.setTimeToLive(3600); registrations.updateRegistration(registration); // Read the updated registration from the data store. - result = registrations.getRegistration(username); + result = registrations.getRegistration(username, orgSid); // Validate the results. assertTrue(result.getSid().equals(registration.getSid())); assertTrue(result.getDateCreated().equals(registration.getDateCreated())); @@ -100,6 +102,7 @@ public void createReadUpdateDelete() { assertTrue(result.getLocation().equals(registration.getLocation())); assertTrue(result.getUserAgent().equals(registration.getUserAgent())); assertTrue(result.getTimeToLive() == registration.getTimeToLive()); + assertTrue(result.isWebRTC()); // Delete the registration. registrations.removeRegistration(registration); // Validate that the registration was removed. @@ -109,36 +112,37 @@ public void createReadUpdateDelete() { @Test public void checkHasRegistrationWithoutUA() { final Sid sid = Sid.generate(Sid.Type.REGISTRATION); + final Sid orgSid = Sid.generate(Sid.Type.ORGANIZATION); final DateTime now = DateTime.now(); String username = "tom_" + now; String displayName = "Tom_" + now; - Registration registration = new Registration(sid, now, now, now, "sip:tom@company.com", displayName, username, null, - 3600, "sip:tom@company.com"); + Registration registration = new Registration(sid, "instanceId", now, now, now, "sip:tom@company.com", displayName, username, null, + 3600, "sip:tom@company.com", true, false, orgSid); final RegistrationsDao registrations = manager.getRegistrationsDao(); // Create a new registration in the data store. assertFalse(registrations.hasRegistration(registration)); registrations.addRegistration(registration); assertTrue(registrations.getRegistrations().size() > 0); - assertNotNull(registrations.getRegistration(username)); + assertNotNull(registrations.getRegistration(username, orgSid)); // Expected to fail if UA is null assertFalse(registrations.hasRegistration(registration)); - } @Test public void checkHasRegistrationWithoutDisplayName() { final Sid sid = Sid.generate(Sid.Type.REGISTRATION); + final Sid orgSid = Sid.generate(Sid.Type.ORGANIZATION); final DateTime now = DateTime.now(); String username = "tom_" + now; String displayName = null; - Registration registration = new Registration(sid, now, now, now, "sip:tom@company.com", displayName, username, - "TestUserAgent/1.0", 3600, "sip:tom@company.com"); + Registration registration = new Registration(sid, "instanceId", now, now, now, "sip:tom@company.com", displayName, username, + "TestUserAgent/1.0", 3600, "sip:tom@company.com", false, false, orgSid); final RegistrationsDao registrations = manager.getRegistrationsDao(); // Create a new registration in the data store. assertFalse(registrations.hasRegistration(registration)); registrations.addRegistration(registration); assertTrue(registrations.getRegistrations().size() > 0); - assertNotNull(registrations.getRegistration(username)); + assertNotNull(registrations.getRegistration(username, orgSid)); // Expected to fail if Display Name is null assertFalse(registrations.hasRegistration(registration)); } diff --git a/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/SmsMessagesDaoTest.java b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/SmsMessagesDaoTest.java new file mode 100644 index 0000000000..6631a60b9f --- /dev/null +++ b/restcomm/restcomm.dao/src/test/java/org/restcomm/connect/dao/mybatis/SmsMessagesDaoTest.java @@ -0,0 +1,207 @@ +/* + * 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.dao.mybatis; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.text.ParseException; +import java.util.Currency; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.junit.After; +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.SmsMessage; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public final class SmsMessagesDaoTest { + private static Logger logger = Logger.getLogger(SmsMessagesDaoTest.class); + private static MybatisDaoManager manager; + + public SmsMessagesDaoTest() { + super(); + } + + @Before + public void before() { + final InputStream data = getClass().getResourceAsStream("/mybatis.xml"); + final SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + final SqlSessionFactory factory = builder.build(data); + manager = new MybatisDaoManager(); + manager.start(factory); + } + + @After + public void after() { + manager.shutdown(); + } + + @Test + public void createReadUpdateDelete() { + final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + final URI url = URI.create("2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json"); + final SmsMessage.Builder builder = SmsMessage.builder(); + builder.setSid(sid); + builder.setAccountSid(account); + builder.setApiVersion("2012-04-24"); + builder.setRecipient("+12223334444"); + builder.setSender("+17778889999"); + builder.setBody("Hello World!"); + builder.setStatus(SmsMessage.Status.SENDING); + builder.setDirection(SmsMessage.Direction.INBOUND); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("USD")); + builder.setUri(url); + SmsMessage message = builder.build(); + final SmsMessagesDao messages = manager.getSmsMessagesDao(); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + // Read the message from the data store. + SmsMessage result = messages.getSmsMessage(sid); + // Validate the results. + assertTrue(result.getSid().equals(message.getSid())); + assertTrue(result.getAccountSid().equals(message.getAccountSid())); + assertTrue(result.getApiVersion().equals(message.getApiVersion())); + assertTrue(result.getDateSent() == message.getDateSent()); + assertTrue(result.getRecipient().equals(message.getRecipient())); + assertTrue(result.getSender().equals(message.getSender())); + assertTrue(result.getBody().equals(message.getBody())); + assertTrue(result.getStatus() == message.getStatus()); + assertTrue(result.getDirection() == message.getDirection()); + assertTrue(result.getPrice().equals(message.getPrice())); + assertTrue(result.getPriceUnit().equals(message.getPriceUnit())); + assertTrue(result.getUri().equals(message.getUri())); + // Update the message. + final DateTime now = DateTime.now(); + message = message.setDateSent(now); + message = message.setStatus(SmsMessage.Status.SENT); + messages.updateSmsMessage(message); + // Read the updated message from the data store. + result = messages.getSmsMessage(sid); + // Validate the results. + assertTrue(result.getDateSent().equals(message.getDateSent())); + assertTrue(result.getStatus() == message.getStatus()); + // Delete the message. + messages.removeSmsMessage(sid); + // Validate that the CDR was removed. + assertTrue(messages.getSmsMessage(sid) == null); + } + + private SmsMessage createSms(Sid account, SmsMessage.Direction direction, int i, DateTime date) { + final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); + final URI url = URI.create("2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json"); + final SmsMessage.Builder builder = SmsMessage.builder(); + builder.setSid(sid); + builder.setAccountSid(account); + builder.setApiVersion("2012-04-24"); + builder.setRecipient("+12223334444"); + builder.setSender("+17778889999"); + builder.setBody("Hello World - "+i); + builder.setStatus(SmsMessage.Status.SENDING); + builder.setDirection(direction); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("USD")); + builder.setUri(url); + builder.setDateCreated(date); + SmsMessage message = builder.build(); + return message; + } + + @Test + public void testGetSmsMessagesLastMinute() throws InterruptedException, ParseException { + final SmsMessagesDao messages = manager.getSmsMessagesDao(); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + DateTime oneMinuteAgo = DateTime.now().minusSeconds(58); + for (int i = 0; i < 2; i++) { + SmsMessage message = createSms(account, SmsMessage.Direction.OUTBOUND_API, i, oneMinuteAgo); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + logger.info("Created message: "+message); + } + for (int i = 0; i < 2; i++) { + SmsMessage message = createSms(account, SmsMessage.Direction.OUTBOUND_CALL, i, oneMinuteAgo); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + logger.info("Created message: "+message); + } + for (int i = 0; i < 2; i++) { + SmsMessage message = createSms(account, SmsMessage.Direction.OUTBOUND_REPLY, i, oneMinuteAgo); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + logger.info("Created message: "+message); + } + int lastMessages = messages.getSmsMessagesPerAccountLastPerMinute(account.toString()); + logger.info("SMS Messages last minutes: "+lastMessages); + assertEquals(6, lastMessages); + Thread.sleep(5000); + DateTime oneMinuteLater = DateTime.now(); + for (int i = 0; i < 3; i++) { + SmsMessage message = createSms(account, SmsMessage.Direction.OUTBOUND_CALL, i, oneMinuteLater); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + logger.info("Created message: "+message); + } + lastMessages = messages.getSmsMessagesPerAccountLastPerMinute(account.toString()); + logger.info("SMS Messages last minutes: "+lastMessages); + assertEquals(3, lastMessages); + messages.removeSmsMessages(account); + } + + @Test + public void testReadDeleteByAccount() { + final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); + final Sid account = Sid.generate(Sid.Type.ACCOUNT); + DateTime now = DateTime.now(); + final URI url = URI.create("2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json"); + final SmsMessage.Builder builder = SmsMessage.builder(); + builder.setSid(sid); + builder.setAccountSid(account); + builder.setApiVersion("2012-04-24"); + builder.setDateSent(now); + builder.setRecipient("+12223334444"); + builder.setSender("+17778889999"); + builder.setBody("Hello World!"); + builder.setStatus(SmsMessage.Status.SENDING); + builder.setDirection(SmsMessage.Direction.INBOUND); + builder.setPrice(new BigDecimal("0.00")); + builder.setPriceUnit(Currency.getInstance("GBP")); + builder.setUri(url); + SmsMessage message = builder.build(); + final SmsMessagesDao messages = manager.getSmsMessagesDao(); + // Create a new sms message in the data store. + messages.addSmsMessage(message); + // Validate the results. + assertTrue(messages.getSmsMessages(account).size() == 1); + // Delete the message. + messages.removeSmsMessages(account); + // Validate the results. + assertTrue(messages.getSmsMessages(account).size() == 0); + } +} diff --git a/restcomm/restcomm.dao/src/test/resources/accounts.xml b/restcomm/restcomm.dao/src/test/resources/accounts.xml deleted file mode 100644 index 76d26efaf0..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/accounts.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "account_sid", "type", "status", "auth_token", "role", "uri") - VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{account_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}); - - - - - - - - - - DELETE FROM "restcomm_accounts" WHERE "sid"=#{sid}; - - - - UPDATE "restcomm_accounts" SET "date_updated"=#{date_updated}, "email_address"=#{email_address}, "friendly_name"=#{friendly_name}, - "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/accountsDao/accounts.xml b/restcomm/restcomm.dao/src/test/resources/accountsDao/accounts.xml new file mode 100644 index 0000000000..b3c1d21065 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/accountsDao/accounts.xml @@ -0,0 +1,63 @@ + + + + + + + + INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "parent_sid", "type", "status", "auth_token", "role", "uri", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{parent_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}, #{organization_sid}); + + + + + + + + + + + + DELETE FROM "restcomm_accounts" WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_accounts" SET "date_updated"=#{date_updated}, "email_address"=#{email_address}, "friendly_name"=#{friendly_name}, + "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role} WHERE "sid"=#{sid}; + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/accountsDao/mybatis.xml b/restcomm/restcomm.dao/src/test/resources/accountsDao/mybatis.xml new file mode 100644 index 0000000000..f4d8fc2040 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/accountsDao/mybatis.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/accountsDao/restcomm.script b/restcomm/restcomm.dao/src/test/resources/accountsDao/restcomm.script new file mode 100644 index 0000000000..be47fb4a6d --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/accountsDao/restcomm.script @@ -0,0 +1,55 @@ +SET DATABASE UNIQUE NAME HSQLDB4B9865B1C6 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE FALSE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 10 +SET FILES BACKUP INCREMENT FALSE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 1 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 200 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +SET SCHEMA PUBLIC +CREATE MEMORY TABLE "restcomm_organizations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "domain_name" VARCHAR(255) NOT NULL UNIQUE, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "status" VARCHAR(16)) +CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL, "organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) +SET SCHEMA PUBLIC +INSERT INTO "restcomm_organizations" VALUES('ORafbe225ad37541eba518a74248f0ac4c', 'default.restcomm.com', '2017-04-19 00:00:00.000000000','2017-04-19 00:00:00.000000000', 'active') +INSERT INTO "restcomm_accounts" VALUES('AC00000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','administrator@company.com','Top Level Account',NULL,'Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC00000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC10000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child1@company.com','Child 1','AC00000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC10000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC20000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child2@company.com','Child 2','AC00000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC20000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC11000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child11@company.com','Child 1-1','AC10000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC11000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC12000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child12@company.com','Child 1-2','AC10000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC12000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC11100000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child111@company.com','Child 1-1-1','AC11000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC11100000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC99999999999999999999999999999999','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','lonelyparent@company.com','Lonely Parent',NULL,'Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC99999999999999999999999999999999','ORafbe225ad37541eba518a74248f0ac4c') diff --git a/restcomm/restcomm.dao/src/test/resources/applications.xml b/restcomm/restcomm.dao/src/test/resources/applications.xml deleted file mode 100644 index 81b5edff78..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/applications.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - INSERT INTO "restcomm_applications" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "api_version", - "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", - "voice_caller_id_lookup", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_status_callback", "uri") - VALUES (#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{api_version}, #{voice_url}, #{voice_method}, - #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, #{voice_caller_id_lookup}, - #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_status_callback}, #{uri}); - - - - - - - - DELETE FROM "restcomm_applications" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_applications" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_applications" SET "friendly_name"=#{friendly_name}, "voice_url"=#{voice_url}, "voice_method"=#{voice_method}, - "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, - "status_callback_method"=#{status_callback_method}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "sms_url"=#{sms_url}, - "sms_method"=#{sms_method}, "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, - "sms_status_callback"=#{sms_status_callback} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/applicationsDao/accounts.xml b/restcomm/restcomm.dao/src/test/resources/applicationsDao/accounts.xml new file mode 100644 index 0000000000..e565ac5015 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/applicationsDao/accounts.xml @@ -0,0 +1,63 @@ + + + + + + + + INSERT INTO "restcomm_accounts" ("sid", "date_created", "date_updated", "email_address", "friendly_name", "parent_sid", "type", "status", "auth_token", "role", "uri", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{email_address}, #{friendly_name}, #{parent_sid}, #{type}, #{status}, #{auth_token}, #{role}, #{uri}, #{organization_sid}); + + + + + + + + + + + + DELETE FROM "restcomm_accounts" WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_accounts" SET "date_updated"=#{date_updated}, "email_address"=#{email_address}, "friendly_name"=#{friendly_name}, + "type"=#{type}, "status"=#{status}, "auth_token"=#{auth_token}, "role"=#{role} WHERE "sid"=#{sid}; + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/applicationsDao/applications.xml b/restcomm/restcomm.dao/src/test/resources/applicationsDao/applications.xml new file mode 100644 index 0000000000..6f3b323d2b --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/applicationsDao/applications.xml @@ -0,0 +1,82 @@ + + + + + + + + INSERT INTO "restcomm_applications" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "api_version", + "voice_caller_id_lookup", "uri", "rcml_url", "kind") + VALUES (#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{api_version}, + #{voice_caller_id_lookup}, #{uri}, #{rcml_url}, #{kind}); + + + + + + + + + + + + + DELETE FROM "restcomm_applications" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_applications" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_applications" SET "friendly_name"=#{friendly_name}, "date_updated"=#{date_updated}, + "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "rcml_url"=#{rcml_url}, "kind"=#{kind} + WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/applicationsDao/incoming-phone-numbers.xml b/restcomm/restcomm.dao/src/test/resources/applicationsDao/incoming-phone-numbers.xml new file mode 100644 index 0000000000..749f8019b0 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/applicationsDao/incoming-phone-numbers.xml @@ -0,0 +1,202 @@ + + + + + + INSERT INTO "restcomm_incoming_phone_numbers" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "phone_number", "api_version", + "voice_caller_id_lookup", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", + "voice_application_sid", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_application_sid", "uri", "voice_capable", "sms_capable", + "mms_capable", "fax_capable", "pure_sip", "cost", "ussd_url", "ussd_method", "ussd_fallback_url", "ussd_fallback_method", "ussd_application_sid", "refer_url", "refer_method", "refer_application_sid", "organization_sid") + VALUES(#{sid}, #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, + #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, + #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}, + #{voice_capable}, #{sms_capable}, #{mms_capable}, #{fax_capable}, #{pure_sip}, #{cost}, #{ussd_url}, #{ussd_method}, #{ussd_fallback_url}, + #{ussd_fallback_method}, #{ussd_application_sid}, #{refer_url}, #{refer_method}, #{refer_application_sid}, #{organization_sid}); + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_incoming_phone_numbers" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_incoming_phone_numbers" SET "friendly_name"=#{friendly_name}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "voice_url"=#{voice_url}, + "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, + "status_callback_method"=#{status_callback_method}, "voice_application_sid"=#{voice_application_sid}, "sms_url"=#{sms_url}, "sms_method"=#{sms_method}, + "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, "sms_application_sid"=#{sms_application_sid}, + "voice_capable"=#{voice_capable}, + "sms_capable"=#{sms_capable}, "mms_capable"=#{mms_capable}, "fax_capable"=#{fax_capable}, "ussd_url"=#{ussd_url}, "ussd_method"=#{ussd_method}, + "ussd_fallback_url"=#{ussd_fallback_url}, "ussd_fallback_method"=#{ussd_fallback_method}, "ussd_application_sid"=#{ussd_application_sid}, + "refer_url"=#{refer_url}, "refer_method"=#{refer_method}, "refer_application_sid"=#{refer_application_sid} WHERE "sid"=#{sid}; + + diff --git a/restcomm/restcomm.dao/src/test/resources/applicationsDao/mybatis.xml b/restcomm/restcomm.dao/src/test/resources/applicationsDao/mybatis.xml new file mode 100644 index 0000000000..7564bfb6a3 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/applicationsDao/mybatis.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/applicationsDao/restcomm.script b/restcomm/restcomm.dao/src/test/resources/applicationsDao/restcomm.script new file mode 100644 index 0000000000..0b590026f5 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/applicationsDao/restcomm.script @@ -0,0 +1,62 @@ +SET DATABASE UNIQUE NAME HSQLDB4B9865B1C6 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE FALSE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 10 +SET FILES BACKUP INCREMENT FALSE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 1 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 200 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +SET SCHEMA PUBLIC +CREATE MEMORY TABLE "restcomm_organizations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "domain_name" VARCHAR(255) NOT NULL UNIQUE, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "status" VARCHAR(16)) +CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL, "organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') +CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"uri" LONGVARCHAR NOT NULL,"rcml_url" LONGVARCHAR, "kind" VARCHAR(5)) +CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(30) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN, "pure_sip" BOOLEAN,"cost" VARCHAR(10), "ussd_url" LONGVARCHAR, "ussd_method" VARCHAR(4), "ussd_fallback_url" LONGVARCHAR, "ussd_fallback_method" VARCHAR(4), "ussd_application_sid" VARCHAR(34), "refer_url" LONGVARCHAR, "refer_method" VARCHAR(4), "refer_application_sid" VARCHAR(34), "organization_sid" VARCHAR(34) NOT NULL) +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) +SET SCHEMA PUBLIC +INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','administrator@company.com','Default Administrator Account',NULL,'Full','uninitialized','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_applications" VALUES('AP73926e7113fa4d95981aa96b76eca854','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','rvdCollectVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP81cf45088cba4abcac1261385916d582','2015-09-23 06:56:17.977000','2015-09-23 06:56:17.977000','rvdESDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP81cf45088cba4abcac1261385916d582','/restcomm-rvd/services/apps/AP81cf45088cba4abcac1261385916d582/controller','voice') +INSERT INTO "restcomm_applications" VALUES('APb70c33bf0b6748f09eaec97030af36f3','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','rvdSayVerbDemo','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APb70c33bf0b6748f09eaec97030af36f3','/restcomm-rvd/services/apps/APb70c33bf0b6748f09eaec97030af36f3/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP00000000000000000000000000000004','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','Lonely app','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP00000000000000000000000000000004','/restcomm-rvd/services/apps/AP00000000000000000000000000000004/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP00000000000000000000000000000005','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','App bound to number owned by other account','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP00000000000000000000000000000005','/restcomm-rvd/services/apps/AP00000000000000000000000000000005/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP00000000000000000000000000000006','2015-09-23 06:56:26.120000','2015-09-23 06:56:26.120000','App belongs to other account','AC00000000000000000000000000000002','2012-04-24',FALSE,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP00000000000000000000000000000006','/restcomm-rvd/services/apps/AP00000000000000000000000000000006/controller','voice') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNc2b81d68a221482ea387b6b4e2cbd9d7','2014-02-17 22:36:58.008000000','2014-02-17 22:36:58.008000000','This makes a call to a basic RVD app ','ACae6e420f425248d6a26948c17a9e2acf','+1239','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','APb70c33bf0b6748f09eaec97030af36f3',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNc2b81d68a221482ea387b6b4e2cbd9d7',NULL,NULL,NULL,NULL,TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000000','2014-02-17 22:37:08.709000000','This is an IVR app that maps user input to specific action','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP73926e7113fa4d95981aa96b76eca854',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',NULL,NULL,NULL,NULL,TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PNb43ed9e641364277b6432547ff1109e9','2014-02-17 22:37:19.392000000','2014-02-17 22:37:19.392000000','RVD external services app, customer ID 1 or 2 ','ACae6e420f425248d6a26948c17a9e2acf','+1241','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP81cf45088cba4abcac1261385916d582',NULL,'POST',NULL,'POST',NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNb43ed9e641364277b6432547ff1109e9',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN00000000000000000000000000000001','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','Test SMS app1 ','ACae6e420f425248d6a26948c17a9e2acf','4455','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST','AP73926e7113fa4d95981aa96b76eca854','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN00000000000000000000000000000002','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','Test USSD app2 ','ACae6e420f425248d6a26948c17a9e2acf','4456','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST','AP73926e7113fa4d95981aa96b76eca854','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,'AP73926e7113fa4d95981aa96b76eca854', NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN00000000000000000000000000000003','2013-10-11 14:56:08.549000000','2013-10-11 14:56:08.549000000','Number owned by other account ','AC00000000000000000000000000000002','4457','2012-04-24',FALSE,'/restcomm/demos/hello-world.xml','POST',NULL,'POST',NULL,'POST',NULL,NULL,'POST',NULL,'POST','AP00000000000000000000000000000005','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN146638eec1e2415d832785e30d227598',NULL,NULL,NULL,NULL, TRUE,'0.0',NULL,NULL,NULL,NULL,'AP00000000000000000000000000000005', NULL, NULL, NULL, 'ORafbe225ad37541eba518a74248f0ac4c') diff --git a/restcomm/restcomm.dao/src/test/resources/call-detail-records.xml b/restcomm/restcomm.dao/src/test/resources/call-detail-records.xml deleted file mode 100644 index b78c122b1e..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/call-detail-records.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - INSERT INTO "restcomm_call_detail_records" ("sid", "parent_call_sid", "date_created", "date_updated", "account_sid", "recipient", "sender", "phone_number_sid", "status", - "start_time", "end_time", "duration", "price", "direction", "answered_by", "api_version", "forwarded_from", "caller_name", "uri") VALUES (#{sid}, #{parent_call_sid}, #{date_created}, - #{date_updated}, #{account_sid}, #{to}, #{from}, #{phone_number_sid}, #{status}, #{start_time}, #{end_time}, #{duration}, #{price}, #{direction}, - #{answered_by}, #{api_version}, #{forwarded_from}, #{caller_name}, #{uri}); - - - - - - - - - - - - - - - - - - DELETE FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_call_detail_records" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_call_detail_records" SET "date_updated"=#{date_updated}, "status"=#{status}, "start_time"=#{start_time}, "end_time"=#{end_time}, "duration"=#{duration}, - "price"=#{price}, "answered_by"=#{answered_by} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/call-detail-records.xml b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/call-detail-records.xml new file mode 100644 index 0000000000..c7a7129620 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/call-detail-records.xml @@ -0,0 +1,196 @@ + + + + + + INSERT INTO "restcomm_call_detail_records" ("sid", "instanceid", "parent_call_sid", "date_created", "date_updated", "account_sid", "recipient", "sender", "phone_number_sid", "status", + "start_time", "end_time", "duration", "price", "direction", "answered_by", "api_version", "forwarded_from", "caller_name", "uri", "call_path", "ring_duration", "conference_sid", "muted", "start_conference_on_enter", "end_conference_on_exit", "on_hold") + VALUES (#{sid}, #{instanceid}, #{parent_call_sid}, #{date_created}, + #{date_updated}, #{account_sid}, #{to}, #{from}, #{phone_number_sid}, #{status}, #{start_time}, #{end_time}, #{duration}, #{price}, #{direction}, + #{answered_by}, #{api_version}, #{forwarded_from}, #{caller_name}, #{uri}, #{call_path}, #{ring_duration}, #{conference_sid}, #{muted}, #{start_conference_on_enter}, #{end_conference_on_exit}, #{on_hold}); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM "restcomm_call_detail_records" WHERE "sid"=#{sid}; + + + + DELETE FROM "restcomm_call_detail_records" WHERE "account_sid"=#{account_sid}; + + + + UPDATE "restcomm_call_detail_records" SET "date_updated"=#{date_updated}, "status"=#{status}, "start_time"=#{start_time}, "end_time"=#{end_time}, "duration"=#{duration}, + "price"=#{price}, "answered_by"=#{answered_by}, "forwarded_from"=#{forwarded_from}, "ring_duration"=#{ring_duration}, "conference_sid"=#{conference_sid}, "muted"=#{muted}, "start_conference_on_enter"=#{start_conference_on_enter}, "end_conference_on_exit"=#{end_conference_on_exit}, "on_hold"=#{on_hold} WHERE "sid"=#{sid}; + + + + UPDATE "restcomm_call_detail_records" + SET "status"='COMPLETED' + WHERE "instanceid"=#{instanceid} AND (UPPER("status") = ('IN_PROGRESS') OR + UPPER("status") = ('IN-PROGRESS') OR UPPER("status") = ('RINGING') OR UPPER("status") = ('QUEUED')); + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/mybatis.xml b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/mybatis.xml new file mode 100644 index 0000000000..25bff569f0 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/mybatis.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/restcomm.script b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/restcomm.script new file mode 100644 index 0000000000..06b01a3b52 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/callDetailRecordsDao/restcomm.script @@ -0,0 +1,145 @@ +SET DATABASE UNIQUE NAME HSQLDB4B9865B1C6 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE FALSE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 10 +SET FILES BACKUP INCREMENT FALSE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 1 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 200 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +SET SCHEMA PUBLIC +CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(1000) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(1000),"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(30) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(20) NOT NULL,"start_time" DATETIME,"end_time" DATETIME,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(20) NOT NULL,"answered_by" VARCHAR(64),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(30),"caller_name" VARCHAR(50),"uri" LONGVARCHAR NOT NULL, "call_path" VARCHAR(255),"ring_duration" INTEGER, "instanceid" VARCHAR(255) NOT NULL, "conference_sid" VARCHAR(34),"muted" BOOLEAN, "start_conference_on_enter" BOOLEAN, "end_conference_on_exit" BOOLEAN, "on_hold" BOOLEAN) +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) +SET SCHEMA PUBLIC +INSERT INTO "restcomm_call_detail_records" VALUES('CA01a09068a1f348269b6670ef599a6e57',NULL,'2013-08-23 14:30:07.820000000','2013-08-23 14:30:08.081000000','AC00000000000000000000000000000000','Anonymous','+15126002188',NULL,'in-progress','2013-08-23 14:30:08.081000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA01a09068a1f348269b6670ef599a6e57', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0263e1e3ff024c03a66af08419f171e7',NULL,'2013-08-05 18:50:17.769000000','2013-08-05 18:50:17.818000000','AC00000000000000000000000000000000','13522703400','+13052406432',NULL,'in-progress','2013-08-05 18:50:17.818000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0263e1e3ff024c03a66af08419f171e7', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0274d5da7193430f9b5b566fde81f924',NULL,'2013-08-27 14:02:23.775000000','2013-08-27 14:02:23.900000000','AC00000000000000000000000000000000','+302109762259','+15126002188',NULL,'in-progress','2013-08-27 14:02:23.900000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0274d5da7193430f9b5b566fde81f924', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA042b13b97e9044eda8e2c1290b40ecae',NULL,'2013-07-31 14:20:39.804000000','2013-07-31 14:20:40.186000000','AC00000000000000000000000000000000','+1011420534008567','+15126002188',NULL,'in-progress','2013-07-31 14:20:40.186000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA042b13b97e9044eda8e2c1290b40ecae', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA04625ae86bf441b8a2d0aebb4d129537',NULL,'2013-09-10 14:03:36.496000000','2013-09-10 14:03:36.871000000','AC00000000000000000000000000000000','+302109762259','+15126002188',NULL,'in-progress','2013-09-10 14:03:36.871000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA04625ae86bf441b8a2d0aebb4d129537', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA04f4ed662d2d4d278486392670eab469',NULL,'2013-08-22 14:00:20.400000000','2013-08-22 14:00:21.179000000','AC00000000000000000000000000000000','+302109762259','+15126002188',NULL,'in-progress','2013-08-22 14:00:21.179000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA04f4ed662d2d4d278486392670eab469', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA04fe49f7cfc74a86a25121f3fe6ef0cc',NULL,'2013-08-23 13:58:46.454000000','2013-08-23 13:58:46.561000000','AC00000000000000000000000000000000','19524007323','+15126002188',NULL,'in-progress','2013-08-23 13:58:46.561000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA04fe49f7cfc74a86a25121f3fe6ef0cc', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0587fa4500f746a8bddca55efc53011c',NULL,'2013-08-30 16:28:33.403000000','2013-08-30 16:28:44.376000000','AC00000000000000000000000000000000','+302118009620','+15126002188',NULL,'completed','2013-08-30 16:28:33.500000000','2013-08-30 16:28:44.376000000',10,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0587fa4500f746a8bddca55efc53011c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA05c8c9f48a2c48aca682c75f06e0c0ae',NULL,'2013-08-22 14:14:24.479000000','2013-08-22 14:14:24.582000000','AC00000000000000000000000000000000','Anonymous','+15126002188',NULL,'in-progress','2013-08-22 14:14:24.582000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA05c8c9f48a2c48aca682c75f06e0c0ae', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA066055a5680c43129d3d9d5ce8c2b839',NULL,'2013-07-30 15:08:21.228000000','2013-07-30 15:08:21.601000000','AC00000000000000000000000000000000','15123663011','+15126002188',NULL,'in-progress','2013-07-30 15:08:21.601000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA066055a5680c43129d3d9d5ce8c2b839', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA074b489546484e009b645c7c71a24fb7',NULL,'2013-08-09 15:25:31.303000000','2013-08-09 15:25:40.835000000','AC00000000000000000000000000000000','14582010335','+17863580884',NULL,'completed','2013-08-09 15:25:32.320000000','2013-08-09 15:25:40.835000000',8,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA074b489546484e009b645c7c71a24fb7', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA07da82df379b4dcb95607821562cfd61',NULL,'2013-08-06 20:08:35.896000000','2013-08-06 20:08:45.274000000','AC00000000000000000000000000000000','14582010335','+17863580884',NULL,'completed','2013-08-06 20:08:36.980000000','2013-08-06 20:08:45.274000000',8,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA07da82df379b4dcb95607821562cfd61', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA08d5d473bf894eb59bab6071a5f8d695',NULL,'2013-07-20 13:59:02.054000000','2013-07-20 13:59:03.157000000','AC11111111111111111111111111111111','19549376176','+15126002188',NULL,'in-progress','2013-07-20 13:59:03.157000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA08d5d473bf894eb59bab6071a5f8d695', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0928cf4a95c342d4ba569243c3cb2c4f',NULL,'2013-07-13 16:01:14.576000000','2013-07-13 16:01:17.235000000','AC11111111111111111111111111111111','15613735718','+17863580884',NULL,'completed','2013-07-13 16:01:14.639000000','2013-07-13 16:01:17.235000000',2,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0928cf4a95c342d4ba569243c3cb2c4f', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0a725b0ae748495cb156295ab1a40539',NULL,'2013-07-15 14:44:51.284000000','2013-07-15 14:44:51.359000000','AC11111111111111111111111111111111','150624102585','+17863580884',NULL,'in-progress','2013-07-15 14:44:51.359000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0a725b0ae748495cb156295ab1a40539', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0b1a449905bf4ccfb1424cb800ecbafd',NULL,'2013-07-31 14:21:00.429000000','2013-07-31 14:21:00.740000000','AC11111111111111111111111111111111','15127829359','+15126002188',NULL,'in-progress','2013-07-31 14:21:00.740000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0b1a449905bf4ccfb1424cb800ecbafd', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0b7734624fc84cef9cc562bbfab9dfaf',NULL,'2013-08-14 13:33:58.099000000','2013-08-14 13:33:59.079000000','AC11111111111111111111111111111111','Anonymous','+15126002188',NULL,'in-progress','2013-08-14 13:33:59.079000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0b7734624fc84cef9cc562bbfab9dfaf', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0bb02739fe5f47398ca1f4c8fe3543b3',NULL,'2013-07-16 14:05:34.019000000','2013-07-16 14:05:34.077000000','AC22222222222222222222222222222222','19549376176','+17863580884',NULL,'in-progress','2013-07-16 14:05:34.077000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0bb02739fe5f47398ca1f4c8fe3543b3', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0c37671d222d426ebf19de8e3a68479c',NULL,'2013-09-30 14:11:53.050000000','2013-09-30 14:11:53.151000000','AC22222222222222222222222222222222','15129703297','+15126002188',NULL,'in-progress','2013-09-30 14:11:53.151000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0c37671d222d426ebf19de8e3a68479c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0d89f0de81af460f9eaa8cb33f607281',NULL,'2013-07-16 16:17:42.890000000','2013-07-16 16:17:43.608000000','AC22222222222222222222222222222222','19549376176','+17863580884',NULL,'in-progress','2013-07-16 16:17:43.608000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0d89f0de81af460f9eaa8cb33f607281', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0edaf158e97d4caf98baeaa5ebe5d3e3',NULL,'2013-08-29 14:11:53.142000000','2013-08-29 14:11:53.300000000','AC22222222222222222222222222222222','Anonymous','+15126002188',NULL,'in-progress','2013-08-29 14:11:53.300000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0edaf158e97d4caf98baeaa5ebe5d3e3', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0f1c2f21f2024ec0b5e366ba50b11cb5',NULL,'2013-07-18 14:02:49.422000000','2013-07-18 14:02:50.256000000','AC22222222222222222222222222222222','16617480241','+15126002188',NULL,'in-progress','2013-07-18 14:02:50.256000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0f1c2f21f2024ec0b5e366ba50b11cb5', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA0f33df07435744f18cb28d79502ea6b1',NULL,'2013-09-02 13:59:31.003000000','2013-09-02 13:59:32.140000000','AC22222222222222222222222222222222','Anonymous','+15126002188',NULL,'in-progress','2013-09-02 13:59:32.140000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA0f33df07435744f18cb28d79502ea6b1', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA108b4ea1355146bb944c8d4214788134',NULL,'2013-07-26 15:01:26.035000000','2013-07-26 15:01:26.258000000','AC22222222222222222222222222222222','Anonymous','+15126002188',NULL,'in-progress','2013-07-26 15:01:26.258000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA108b4ea1355146bb944c8d4214788134', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA10b568df59c84dc3aae6778d15bde115',NULL,'2013-08-14 14:09:54.496000000','2013-08-14 14:09:55.662000000','AC22222222222222222222222222222222','19549376176','+15126002188',NULL,'in-progress','2013-08-14 14:09:55.662000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA10b568df59c84dc3aae6778d15bde115', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1388a141e07e4d47882a093c8aa2c5d5',NULL,'2013-08-29 14:02:00.302000000','2013-08-29 14:02:01.400000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-08-29 14:02:01.400000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1388a141e07e4d47882a093c8aa2c5d5', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA150cf453d42d40a1a650e6133daf3052',NULL,'2013-08-23 13:58:19.049000000','2013-08-23 13:58:19.237000000','ACae6e420f425248d6a26948c17a9e2acf','17639233833','+15126002188',NULL,'in-progress','2013-08-23 13:58:19.237000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA150cf453d42d40a1a650e6133daf3052', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA163b469ef6eb4f11b36ac2fcb151e1c7',NULL,'2013-09-15 15:04:14.773000000','2013-09-15 15:04:16.312000000','ACae6e420f425248d6a26948c17a9e2acf','15125377935','+15126002188',NULL,'in-progress','2013-09-15 15:04:16.312000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA163b469ef6eb4f11b36ac2fcb151e1c7', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA16d7b9acdc684cebae09290aaedc0072',NULL,'2013-08-23 14:07:03.054000000','2013-08-23 14:07:03.401000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-08-23 14:07:03.401000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA16d7b9acdc684cebae09290aaedc0072', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA172a3a745e764aa297574997620ff34e',NULL,'2013-07-26 13:59:32.435000000','2013-07-26 13:59:32.580000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+15126002188',NULL,'in-progress','2013-07-26 13:59:32.580000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA172a3a745e764aa297574997620ff34e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA17a357f26864476698bbf4e33850f433',NULL,'2013-07-15 15:13:31.203000000','2013-07-15 15:13:31.260000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+17863580884',NULL,'in-progress','2013-07-15 15:13:31.260000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA17a357f26864476698bbf4e33850f433', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA17a7448ad51849f7ac592ee85f01f42f',NULL,'2013-08-07 13:31:04.975000000','2013-08-07 13:31:05.739000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+15126002188',NULL,'in-progress','2013-08-07 13:31:05.739000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA17a7448ad51849f7ac592ee85f01f42f', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA17e903396f6c4a54854dd783b10c0926',NULL,'2013-09-24 15:00:04.370000000','2013-09-24 15:00:04.492000000','ACae6e420f425248d6a26948c17a9e2acf','15129703297','+15126002188',NULL,'in-progress','2013-09-24 15:00:04.492000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA17e903396f6c4a54854dd783b10c0926', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA18a1383747774188bfa31adc1619ce14',NULL,'2013-07-16 11:16:10.919000000','2013-07-16 11:16:10.981000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+17863580884',NULL,'in-progress','2013-07-16 11:16:10.981000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA18a1383747774188bfa31adc1619ce14', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1973890498be4132b04919c6071200e9',NULL,'2013-07-16 15:16:47.457000000','2013-07-16 15:16:47.520000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+17863580884',NULL,'in-progress','2013-07-16 15:16:47.520000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1973890498be4132b04919c6071200e9', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA19c6a879014747c9a3f00944b95e6c98',NULL,'2013-09-26 15:00:39.561000000','2013-09-26 15:00:39.740000000','ACae6e420f425248d6a26948c17a9e2acf','16099450692','+15126002188',NULL,'in-progress','2013-09-26 15:00:39.740000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA19c6a879014747c9a3f00944b95e6c98', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1a1157638147464ca6aa73b0836c829b',NULL,'2013-09-10 11:01:48.012000000','2013-09-10 11:01:56.028000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'completed','2013-09-10 11:01:48.613000000','2013-09-10 11:01:56.028000000',7,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1a1157638147464ca6aa73b0836c829b', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1a392e3c70914e86af13807ce4d96d6f',NULL,'2013-07-23 14:01:35.839000000','2013-07-23 14:01:36.139000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+15126002188',NULL,'in-progress','2013-07-23 14:01:36.139000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1a392e3c70914e86af13807ce4d96d6f', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1a510cdadee54d01a7e6fe61230c683c',NULL,'2013-08-28 13:24:41.292000000','2013-08-28 13:24:41.896000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'completed','2013-08-28 13:24:41.422000000','2013-08-28 13:24:41.896000000',0,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1a510cdadee54d01a7e6fe61230c683c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1ab64912d0b242b0bbbf1ec3d00ba07e',NULL,'2013-08-19 13:33:51.707000000','2013-08-19 13:33:51.878000000','ACae6e420f425248d6a26948c17a9e2acf','+919960639901','+15126002188',NULL,'in-progress','2013-08-19 13:33:51.878000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1ab64912d0b242b0bbbf1ec3d00ba07e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1b416023bde1434ab1d342e8de5d49c8',NULL,'2013-09-02 09:36:24.144000000','2013-09-02 09:36:30.239000000','ACae6e420f425248d6a26948c17a9e2acf','gvagenas','+15126002188',NULL,'completed','2013-09-02 09:36:24.321000000','2013-09-02 09:36:30.239000000',5,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1b416023bde1434ab1d342e8de5d49c8', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1bc74a459af64016b466ae4f3e1a9ecc',NULL,'2013-08-21 14:12:58.816000000','2013-08-21 14:13:00.838000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-08-21 14:13:00.838000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1bc74a459af64016b466ae4f3e1a9ecc', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1cbea362aaef4482a941af600f3f7f05',NULL,'2013-07-16 14:38:39.930000000','2013-07-16 14:38:39.980000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+17863580884',NULL,'in-progress','2013-07-16 14:38:39.980000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1cbea362aaef4482a941af600f3f7f05', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1db27760b8254bb5988da5479d55c5af',NULL,'2013-09-16 15:06:30.886000000','2013-09-16 15:06:31.110000000','ACae6e420f425248d6a26948c17a9e2acf','15129998486','+15126002188',NULL,'in-progress','2013-09-16 15:06:31.110000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1db27760b8254bb5988da5479d55c5af', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e26fd6e297a42e6b5f2cfb5fc35a0c7',NULL,'2013-08-21 13:31:54.127000000','2013-08-21 13:31:54.387000000','ACae6e420f425248d6a26948c17a9e2acf','15125377935','+15126002188',NULL,'in-progress','2013-08-21 13:31:54.387000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e26fd6e297a42e6b5f2cfb5fc35a0c7', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e2cc9e853654f5283e3335b7999ce85',NULL,'2013-07-29 08:15:59.265000000','2013-07-29 08:16:00.160000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+15126002188',NULL,'in-progress','2013-07-29 08:16:00.160000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e2cc9e853654f5283e3335b7999ce85', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e4841845f764721a2676e613a2ef4c3',NULL,'2013-07-15 14:38:59.190000000','2013-07-15 14:38:59.262000000','ACae6e420f425248d6a26948c17a9e2acf','150624102585','+17863580884',NULL,'in-progress','2013-07-15 14:38:59.262000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e4841845f764721a2676e613a2ef4c3', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e5e1fcffbea41c1a7735c00fe5b8ed4',NULL,'2013-09-04 16:58:08.432000000','2013-09-04 16:58:09.419000000','ACae6e420f425248d6a26948c17a9e2acf','Restricted','+15126002188',NULL,'in-progress','2013-09-04 16:58:09.419000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e5e1fcffbea41c1a7735c00fe5b8ed4', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e5fc369f0c64928a954e06e92db408e',NULL,'2013-08-22 14:11:06.669000000','2013-08-22 14:11:06.842000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-08-22 14:11:06.842000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e5fc369f0c64928a954e06e92db408e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e758923b4e5498f9b50d84d25a27595',NULL,'2013-07-16 14:04:58.852000000','2013-07-16 14:04:58.897000000','ACae6e420f425248d6a26948c17a9e2acf','1302109762259','+17863580884',NULL,'in-progress','2013-07-16 14:04:58.897000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e758923b4e5498f9b50d84d25a27595', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1e842cb845d5452d83270c019b2f765e',NULL,'2013-09-10 11:02:06.758000000','2013-09-10 11:02:06.871000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-09-10 11:02:06.871000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1e842cb845d5452d83270c019b2f765e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1ea371ea214b481393283262f064c7e6',NULL,'2013-07-18 14:02:34.466000000','2013-07-18 14:02:34.636000000','ACae6e420f425248d6a26948c17a9e2acf','+101133951050502','+15126002188',NULL,'in-progress','2013-07-18 14:02:34.636000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1ea371ea214b481393283262f064c7e6', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1ecf4436f8e94a92b5cbae92122d98ac',NULL,'2013-09-06 08:02:37.438000000','2013-09-06 08:02:44.257000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'completed','2013-09-06 08:02:38.919000000','2013-09-06 08:02:44.257000000',5,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1ecf4436f8e94a92b5cbae92122d98ac', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1ed18f7929f644c59c258faed10a9e3c',NULL,'2013-07-15 14:41:14.625000000','2013-07-15 14:41:14.719000000','ACae6e420f425248d6a26948c17a9e2acf','anonymous','+17863580884',NULL,'in-progress','2013-07-15 14:41:14.719000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1ed18f7929f644c59c258faed10a9e3c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA1fec48c624d5416d8c8f01fe9294d159',NULL,'2013-07-16 14:26:55.879000000','2013-07-16 14:26:55.940000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+17863580884',NULL,'in-progress','2013-07-16 14:26:55.940000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA1fec48c624d5416d8c8f01fe9294d159', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2196f6ad7aa249f9ae112a475311124c',NULL,'2013-07-15 14:51:01.337000000','2013-07-15 14:51:01.421000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+17863580884',NULL,'in-progress','2013-07-15 14:51:01.421000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2196f6ad7aa249f9ae112a475311124c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA22145022065845f19ccd4c0952bb825f',NULL,'2013-09-26 14:35:01.585000000','2013-09-26 14:35:05.008000000','ACae6e420f425248d6a26948c17a9e2acf','Restricted','+15126002188',NULL,'completed','2013-09-26 14:35:02.852000000','2013-09-26 14:35:05.008000000',2,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA22145022065845f19ccd4c0952bb825f', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA22ac5fd16a954c339f33519bdfe4af78',NULL,'2013-07-05 22:15:53.590000000','2013-07-05 22:15:54.120000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+17863580884',NULL,'completed','2013-07-05 22:15:54.120000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA22ac5fd16a954c339f33519bdfe4af78', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA22be3790638149358dbd81dc8fb41121',NULL,'2013-09-16 15:01:49.558000000','2013-09-16 15:01:50.594000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-09-16 15:01:50.594000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA22be3790638149358dbd81dc8fb41121', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA231e2ce7733148b2a5a28a3717abd808',NULL,'2013-09-22 02:25:14.931000000','2013-09-22 02:25:14.990000000','ACae6e420f425248d6a26948c17a9e2acf','19252038899','+13057486960',NULL,'in-progress','2013-09-22 02:25:14.990000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA231e2ce7733148b2a5a28a3717abd808', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2450c71026bc49c0bbcd3db9a97db03c',NULL,'2013-09-24 14:59:24.028000000','2013-09-24 14:59:25.253000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-09-24 14:59:25.253000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2450c71026bc49c0bbcd3db9a97db03c', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA24954dcb072a4c478fbcda95a49c974a',NULL,'2013-07-26 13:54:40.516000000','2013-07-26 13:54:41.706000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-07-26 13:54:41.706000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA24954dcb072a4c478fbcda95a49c974a', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA25864e0d271143aaa084ce264e85c633',NULL,'2013-08-24 16:52:48.672000000','2013-08-24 16:52:48.719000000','ACae6e420f425248d6a26948c17a9e2acf','13522703400','+13052406432',NULL,'in-progress','2013-08-24 16:52:48.719000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA25864e0d271143aaa084ce264e85c633', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA260fbe8a50c24fffbd591fb5a64a18a5',NULL,'2013-09-30 14:11:34.485000000','2013-09-30 14:11:34.771000000','ACae6e420f425248d6a26948c17a9e2acf','12024991615','+15126002188',NULL,'in-progress','2013-09-30 14:11:34.771000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA260fbe8a50c24fffbd591fb5a64a18a5', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA263f1141a88c4633bd4b3767d78b9182',NULL,'2013-09-26 20:02:27.618000000','2013-09-26 20:02:27.730000000','ACae6e420f425248d6a26948c17a9e2acf','15129703297','+15126002188',NULL,'in-progress','2013-09-26 20:02:27.730000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA263f1141a88c4633bd4b3767d78b9182', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA27e9a17eaf574afaa9dac055fae2795e',NULL,'2013-08-06 09:00:22.915000000','2013-08-06 09:00:23.999000000','ACae6e420f425248d6a26948c17a9e2acf','1918067078500','+15126002188',NULL,'in-progress','2013-08-06 09:00:23.999000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA27e9a17eaf574afaa9dac055fae2795e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA28c98c1f915f4b658aa03e65816e7d0e',NULL,'2013-07-16 14:01:36.609000000','2013-07-16 14:01:36.675000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+17863580884',NULL,'in-progress','2013-07-16 14:01:36.675000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA28c98c1f915f4b658aa03e65816e7d0e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA296e8c25e2a74464a9384f7b8a0dfa82',NULL,'2013-07-24 14:04:13.185000000','2013-07-24 14:04:13.954000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+15126002188',NULL,'completed','2013-07-24 14:04:13.458000000','2013-07-24 14:04:13.954000000',0,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA296e8c25e2a74464a9384f7b8a0dfa82', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA298e3c55f6d64542bc93471fcab05f80',NULL,'2013-09-23 16:32:25.361000000','2013-09-23 16:32:25.953000000','ACae6e420f425248d6a26948c17a9e2acf','15129703297','+15126002188',NULL,'in-progress','2013-09-23 16:32:25.953000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA298e3c55f6d64542bc93471fcab05f80', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2acf424a9baa48529bb1ea1de8c66f10',NULL,'2013-07-26 15:09:34.659000000','2013-07-26 15:09:34.886000000','ACae6e420f425248d6a26948c17a9e2acf','+101133679364376','+15126002188',NULL,'in-progress','2013-07-26 15:09:34.886000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2acf424a9baa48529bb1ea1de8c66f10', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2ad7d3393f574880894f158cb0434525',NULL,'2013-09-12 14:05:23.533000000','2013-09-12 14:05:23.809000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-09-12 14:05:23.809000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2ad7d3393f574880894f158cb0434525', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2ae1f318bded4239b8a0f2a2b3cae6cc',NULL,'2013-09-20 16:01:15.964000000','2013-09-20 16:01:16.032000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+13052406432',NULL,'in-progress','2013-09-20 16:01:16.032000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2ae1f318bded4239b8a0f2a2b3cae6cc', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2b53f9eb486e482c9c9998fa72edb3f8',NULL,'2013-09-24 15:05:17.846000000','2013-09-24 15:05:17.912000000','ACae6e420f425248d6a26948c17a9e2acf','13522703400','+13052406432',NULL,'in-progress','2013-09-24 15:05:17.912000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2b53f9eb486e482c9c9998fa72edb3f8', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2be084d1e74f4011b9e2bef4e9b00c63',NULL,'2013-07-25 14:05:49.276000000','2013-07-25 14:05:49.418000000','ACae6e420f425248d6a26948c17a9e2acf','16617480241','+15126002188',NULL,'in-progress','2013-07-25 14:05:49.418000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2be084d1e74f4011b9e2bef4e9b00c63', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2c071079d53344879d5798d124946278',NULL,'2013-08-19 13:42:14.130000000','2013-08-19 13:42:14.342000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-08-19 13:42:14.342000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2c071079d53344879d5798d124946278', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2c0dbf3b39364240b961d66dccbb26fe',NULL,'2013-09-03 20:59:41.986000000','2013-09-03 20:59:42.760000000','ACae6e420f425248d6a26948c17a9e2acf','+5127829359','+15126002188',NULL,'in-progress','2013-09-03 20:59:42.760000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2c0dbf3b39364240b961d66dccbb26fe', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2cf8204f8e5542b4b0e277fe600ee80e',NULL,'2013-08-20 13:17:40.434000000','2013-08-20 13:17:41.738000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-08-20 13:17:41.738000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2cf8204f8e5542b4b0e277fe600ee80e', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2cfe293d57044f2ba7131634e655e424',NULL,'2013-09-24 15:00:48.573000000','2013-09-24 15:00:48.771000000','ACae6e420f425248d6a26948c17a9e2acf','15148628818','+15126002188',NULL,'in-progress','2013-09-24 15:00:48.771000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2cfe293d57044f2ba7131634e655e424', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2dd57684f8604ed6a6d56615b9009a13',NULL,'2013-07-23 14:05:19.439000000','2013-07-23 14:05:20.018000000','ACae6e420f425248d6a26948c17a9e2acf','16617480241','+15126002188',NULL,'in-progress','2013-07-23 14:05:20.018000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2dd57684f8604ed6a6d56615b9009a13', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA2f223df0546a4df98054ec13b41c7c08',NULL,'2013-07-30 14:01:12.285000000','2013-07-30 14:01:12.843000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+15126002188',NULL,'in-progress','2013-07-30 14:01:12.843000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA2f223df0546a4df98054ec13b41c7c08', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA301b98d7a9af4626ae0679c03d9f91d6',NULL,'2013-09-10 14:02:20.973000000','2013-09-10 14:02:22.093000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+15126002188',NULL,'in-progress','2013-09-10 14:02:22.093000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA301b98d7a9af4626ae0679c03d9f91d6', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA304e3de8814c47769006144f9c4f8403',NULL,'2013-08-27 14:03:31.978000000','2013-08-27 14:03:32.339000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-08-27 14:03:32.339000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA304e3de8814c47769006144f9c4f8403', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA30978f8056d84a8c92ca0c56dbdedefa',NULL,'2013-07-23 14:03:07.943000000','2013-07-23 14:03:08.184000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+17863580884',NULL,'in-progress','2013-07-23 14:03:08.184000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA30978f8056d84a8c92ca0c56dbdedefa', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA31b896c2a34c438686783b541c9b45c4',NULL,'2013-08-23 08:59:04.030000000','2013-08-23 08:59:04.899000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-08-23 08:59:04.899000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA31b896c2a34c438686783b541c9b45c4', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA323ee0ed52a04921a0e3589de719b580',NULL,'2013-08-20 14:01:40.127000000','2013-08-20 14:01:40.300000000','ACae6e420f425248d6a26948c17a9e2acf','15127829359','+15126002188',NULL,'in-progress','2013-08-20 14:01:40.300000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA323ee0ed52a04921a0e3589de719b580', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA327784919c294add9ff9fbcfab2b06f0',NULL,'2013-07-17 14:55:08.374000000','2013-07-17 14:55:08.520000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+15126002188',NULL,'in-progress','2013-07-17 14:55:08.520000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA327784919c294add9ff9fbcfab2b06f0', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA32b6aceb81314166958cbad5bd7b50dd',NULL,'2013-09-15 17:00:42.984000000','2013-09-15 17:00:43.673000000','ACae6e420f425248d6a26948c17a9e2acf','15125377935','+15126002188',NULL,'in-progress','2013-09-15 17:00:43.673000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA32b6aceb81314166958cbad5bd7b50dd', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA333e4d89897a444f8693b3d3f69ae88d',NULL,'2013-08-22 14:07:36.700000000','2013-08-22 14:07:36.862000000','ACae6e420f425248d6a26948c17a9e2acf','15125377935','+15126002188',NULL,'in-progress','2013-08-22 14:07:36.862000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA333e4d89897a444f8693b3d3f69ae88d', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA334affb103354a0aa4cae2a81021cda8',NULL,'2013-08-23 14:05:25.193000000','2013-08-23 14:05:25.580000000','ACae6e420f425248d6a26948c17a9e2acf','+6617480241','+15126002188',NULL,'in-progress','2013-08-23 14:05:25.580000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA334affb103354a0aa4cae2a81021cda8', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA33cd961012db4fb2841c3dcc487f0b22',NULL,'2013-09-13 18:57:15.017000000','2013-09-13 18:57:15.171000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-09-13 18:57:15.171000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA33cd961012db4fb2841c3dcc487f0b22', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA364611927bec421e947661319378594d',NULL,'2013-09-10 14:16:07.633000000','2013-09-10 14:16:07.971000000','ACae6e420f425248d6a26948c17a9e2acf','16617480240','+15126002188',NULL,'in-progress','2013-09-10 14:16:07.971000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA364611927bec421e947661319378594d', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3652685933a84da797dfb56fa9821f6d',NULL,'2013-09-30 14:02:15.218000000','2013-09-30 14:02:16.391000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-09-30 14:02:16.391000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3652685933a84da797dfb56fa9821f6d', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA37d7dd4f168b4a12bb37175409cf908b',NULL,'2013-08-30 13:59:54.157000000','2013-08-30 13:59:54.281000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-08-30 13:59:54.281000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA37d7dd4f168b4a12bb37175409cf908b', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA381dab66fd7e4d7fb9dadd815916d05a',NULL,'2013-07-15 14:28:21.852000000','2013-07-15 14:28:21.917000000','ACae6e420f425248d6a26948c17a9e2acf','133951050502','+17863580884',NULL,'in-progress','2013-07-15 14:28:21.917000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA381dab66fd7e4d7fb9dadd815916d05a', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3904e199445145ed984ce84a0debd311',NULL,'2013-08-06 09:02:53.375000000','2013-08-06 09:02:53.522000000','ACae6e420f425248d6a26948c17a9e2acf','+918067078500','+15126002188',NULL,'in-progress','2013-08-06 09:02:53.522000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3904e199445145ed984ce84a0debd311', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3a28d89482ec4e46a9f1e2ff5c491b74',NULL,'2013-08-26 14:02:20.794000000','2013-08-26 14:02:21.217000000','ACae6e420f425248d6a26948c17a9e2acf','+302109762259','+15126002188',NULL,'in-progress','2013-08-26 14:02:21.217000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3a28d89482ec4e46a9f1e2ff5c491b74', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3b30eb7cc24f47489f53d9e033385a2a',NULL,'2013-08-22 14:13:30.336000000','2013-08-22 14:13:30.501000000','ACae6e420f425248d6a26948c17a9e2acf','Anonymous','+15126002188',NULL,'in-progress','2013-08-22 14:13:30.501000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3b30eb7cc24f47489f53d9e033385a2a', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3c2386d4942f4028b714c24af404c239',NULL,'2013-08-13 14:14:31.402000000','2013-08-13 14:14:32.519000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-08-13 14:14:32.519000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3c2386d4942f4028b714c24af404c239', NULL,NULL, NULL, NULL, NULL) +INSERT INTO "restcomm_call_detail_records" VALUES('CA3d386ded326f4aba9e495959b0ac5218',NULL,'2013-07-17 14:55:01.225000000','2013-07-17 14:55:01.361000000','ACae6e420f425248d6a26948c17a9e2acf','19549376176','+15126002188',NULL,'in-progress','2013-07-17 14:55:01.361000000',NULL,NULL,'0.00','inbound',NULL,'2012-04-24',NULL,NULL,'/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA3d386ded326f4aba9e495959b0ac5218', NULL,NULL, NULL, NULL, NULL) diff --git a/restcomm/restcomm.dao/src/test/resources/clients.xml b/restcomm/restcomm.dao/src/test/resources/clients.xml deleted file mode 100644 index c52b4c780d..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/clients.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - INSERT INTO "restcomm_clients" ("sid", "date_created", "date_updated", "account_sid", "api_version", "friendly_name", "login", "password", - "status", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "voice_application_sid", "uri") VALUES (#{sid}, - #{date_created}, #{date_updated}, #{account_sid}, #{api_version}, #{friendly_name}, #{login}, #{password}, #{status}, #{voice_url}, - #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{voice_application_sid}, #{uri}); - - - - - - - - - - DELETE FROM "restcomm_clients" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_clients" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_clients" SET "friendly_name"=#{friendly_name}, "password"=#{password}, "status"=#{status}, "voice_url"=#{voice_url}, - "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, - "voice_application_sid"=#{voice_application_sid} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/data/restcomm.script b/restcomm/restcomm.dao/src/test/resources/data/restcomm.script index 5e14604f25..2bfd9fdba3 100644 --- a/restcomm/restcomm.dao/src/test/resources/data/restcomm.script +++ b/restcomm/restcomm.dao/src/test/resources/data/restcomm.script @@ -1,28 +1,167 @@ +SET DATABASE UNIQUE NAME HSQLDB4B9865B1C6 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE FALSE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 10 +SET FILES BACKUP INCREMENT FALSE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 1 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 200 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' CREATE SCHEMA PUBLIC AUTHORIZATION DBA -CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_announcements"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34),"gender" VARCHAR(8) NOT NULL,"language" VARCHAR(16) NOT NULL,"text" VARCHAR(32) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL) -CREATE MEMORY TABLE "restcomm_outgoing_caller_ids"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_http_cookies"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"comment" LONGVARCHAR,"domain" LONGVARCHAR,"expiration_date" TIMESTAMP,"name" LONGVARCHAR NOT NULL,"path" LONGVARCHAR,"value" LONGVARCHAR,"version" INTEGER) -CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_caller_id_lookup" BOOLEAN NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_status_callback" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(34),"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(11) NOT NULL,"start_time" TIMESTAMP,"end_time" TIMESTAMP,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(13) NOT NULL,"answered_by" VARCHAR(7),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(15),"caller_name" VARCHAR(30),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_expires" TIMESTAMP NOT NULL,"address_of_record" LONGVARCHAR NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" LONGVARCHAR,"ttl" INTEGER NOT NULL,"location" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_short_codes"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"short_code" INTEGER NOT NULL,"api_version" VARCHAR(10) NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_sent" TIMESTAMP,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"body" VARCHAR(160) NOT NULL,"status" VARCHAR(7) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_transcriptions"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(11) NOT NULL,"recording_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"transcription_text" LONGVARCHAR NOT NULL,"price" VARCHAR(8) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" LONGVARCHAR NOT NULL,"message_text" LONGVARCHAR NOT NULL,"message_date" TIMESTAMP NOT NULL,"request_url" LONGVARCHAR NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" LONGVARCHAR NOT NULL,"response_headers" LONGVARCHAR,"response_body" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_sand_boxes"("date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"pin" VARCHAR(8) NOT NULL,"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY,"phone_number" VARCHAR(15) NOT NULL,"application_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(255),"user_name" VARCHAR(255),"password" VARCHAR(255),"proxy" LONGVARCHAR NOT NULL,"register" BOOLEAN NOT NULL,"ttl" INTEGER NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE USER SA PASSWORD "" +SET SCHEMA PUBLIC +CREATE MEMORY TABLE PUBLIC."restcomm_instance_id"("instance_id" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"host" VARCHAR(255) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_organizations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"domain_name" VARCHAR(255) NOT NULL,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,UNIQUE("domain_name")) +CREATE MEMORY TABLE PUBLIC."restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"email_address" VARCHAR(16777216) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" VARCHAR(16777216) NOT NULL,"organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') +CREATE MEMORY TABLE PUBLIC."restcomm_announcements"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34),"gender" VARCHAR(8) NOT NULL,"language" VARCHAR(16) NOT NULL,"text" VARCHAR(32) NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL,"voice_capable" BOOLEAN,"sms_capable" BOOLEAN,"mms_capable" BOOLEAN,"fax_capable" BOOLEAN,"cost" VARCHAR(10)) +CREATE MEMORY TABLE PUBLIC."restcomm_outgoing_caller_ids"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_http_cookies"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"comment" VARCHAR(16777216),"domain" VARCHAR(16777216),"expiration_date" TIMESTAMP,"name" VARCHAR(16777216) NOT NULL,"path" VARCHAR(16777216),"value" VARCHAR(16777216),"version" INTEGER) +CREATE MEMORY TABLE PUBLIC."restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(30) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" VARCHAR(16777216),"voice_method" VARCHAR(4),"voice_fallback_url" VARCHAR(16777216),"voice_fallback_method" VARCHAR(4),"status_callback" VARCHAR(16777216),"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" VARCHAR(16777216),"sms_method" VARCHAR(4),"sms_fallback_url" VARCHAR(16777216),"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" VARCHAR(16777216) NOT NULL,"voice_capable" BOOLEAN,"sms_capable" BOOLEAN,"mms_capable" BOOLEAN,"fax_capable" BOOLEAN,"pure_sip" BOOLEAN,"cost" VARCHAR(10),"ussd_url" VARCHAR(16777216),"ussd_method" VARCHAR(4),"ussd_fallback_url" VARCHAR(16777216),"ussd_fallback_method" VARCHAR(4),"ussd_application_sid" VARCHAR(34),"refer_url" VARCHAR(16777216),"refer_method" VARCHAR(4),"refer_application_sid" VARCHAR(34),"organization_sid" VARCHAR(34) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"uri" VARCHAR(16777216) NOT NULL,"rcml_url" VARCHAR(16777216),"kind" VARCHAR(5)) +CREATE MEMORY TABLE PUBLIC."restcomm_call_detail_records"("sid" VARCHAR(1000) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(1000),"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(30) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(20) NOT NULL,"start_time" TIMESTAMP,"end_time" TIMESTAMP,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(20) NOT NULL,"answered_by" VARCHAR(64),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(30),"caller_name" VARCHAR(50),"uri" VARCHAR(16777216) NOT NULL,"call_path" VARCHAR(255),"ring_duration" INTEGER,"instanceid" VARCHAR(255) NOT NULL,"conference_sid" VARCHAR(34),"muted" BOOLEAN,"start_conference_on_enter" BOOLEAN,"end_conference_on_exit" BOOLEAN,"on_hold" BOOLEAN,"ms_id" VARCHAR(34)) +CREATE MEMORY TABLE PUBLIC."restcomm_conference_detail_records"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(100) NOT NULL,"friendly_name" VARCHAR(60),"api_version" VARCHAR(10) NOT NULL,"uri" VARCHAR(16777216) NOT NULL,"master_ms_id" VARCHAR(34),"master_conference_endpoint_id" VARCHAR(20),"master_present" BOOLEAN DEFAULT TRUE,"master_ivr_endpoint_id" VARCHAR(20),"master_ivr_endpoint_session_id" VARCHAR(200),"master_bridge_endpoint_id" VARCHAR(20),"master_bridge_endpoint_session_id" VARCHAR(200),"master_bridge_conn_id" VARCHAR(200),"master_ivr_conn_id" VARCHAR(200)) +CREATE MEMORY TABLE PUBLIC."restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" VARCHAR(16777216),"voice_method" VARCHAR(4),"voice_fallback_url" VARCHAR(16777216),"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" VARCHAR(16777216) NOT NULL,"push_client_identity" VARCHAR(34)) +CREATE MEMORY TABLE PUBLIC."restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_expires" TIMESTAMP NOT NULL,"address_of_record" VARCHAR(16777216) NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" VARCHAR(16777216),"ttl" INTEGER NOT NULL,"location" VARCHAR(16777216) NOT NULL,"webrtc" BOOLEAN DEFAULT FALSE,"instanceid" VARCHAR(255),"isLBPresent" BOOLEAN DEFAULT FALSE, "organization_sid" VARCHAR(34)) +CREATE MEMORY TABLE PUBLIC."restcomm_short_codes"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"short_code" INTEGER NOT NULL,"api_version" VARCHAR(10) NOT NULL,"sms_url" VARCHAR(16777216),"sms_method" VARCHAR(4),"sms_fallback_url" VARCHAR(16777216),"sms_fallback_method" VARCHAR(4),"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_sent" TIMESTAMP,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"body" VARCHAR(999) NOT NULL,"status" VARCHAR(20) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" VARCHAR(16777216) NOT NULL,"file_uri" VARCHAR(16777216)) +CREATE MEMORY TABLE PUBLIC."restcomm_transcriptions"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(11) NOT NULL,"recording_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"transcription_text" VARCHAR(16777216),"price" VARCHAR(8) NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" VARCHAR(16777216) NOT NULL,"message_text" VARCHAR(16777216) NOT NULL,"message_date" TIMESTAMP NOT NULL,"request_url" VARCHAR(16777216) NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" VARCHAR(16777216) NOT NULL,"response_headers" VARCHAR(16777216),"response_body" VARCHAR(16777216),"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_sand_boxes"("date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"pin" VARCHAR(8) NOT NULL,"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY,"phone_number" VARCHAR(15) NOT NULL,"application_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" VARCHAR(16777216),"voice_method" VARCHAR(4),"sms_url" VARCHAR(16777216),"sms_method" VARCHAR(4),"status_callback" VARCHAR(16777216),"status_callback_method" VARCHAR(4),"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(255),"user_name" VARCHAR(255),"password" VARCHAR(255),"proxy" VARCHAR(16777216) NOT NULL,"register" BOOLEAN NOT NULL,"ttl" INTEGER NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_media_servers"("ms_id" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL,"local_ip" VARCHAR(34) NOT NULL,"local_port" INTEGER NOT NULL,"remote_ip" VARCHAR(34) NOT NULL,"remote_port" INTEGER NOT NULL,"compatibility" VARCHAR(34) DEFAULT 'rms',"response_timeout" VARCHAR(34),"external_address" VARCHAR(34),UNIQUE("remote_ip")) +ALTER TABLE PUBLIC."restcomm_media_servers" ALTER COLUMN "ms_id" RESTART WITH 1 +CREATE MEMORY TABLE PUBLIC."restcomm_media_resource_broker_entity"("conference_sid" VARCHAR(34) NOT NULL,"slave_ms_id" VARCHAR(34) NOT NULL,"slave_ms_bridge_ep_id" VARCHAR(34),"slave_ms_cnf_ep_id" VARCHAR(34),"is_bridged_together" BOOLEAN DEFAULT FALSE,PRIMARY KEY("conference_sid","slave_ms_id")) +CREATE MEMORY TABLE PUBLIC."restcomm_extensions_configuration"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"extension" VARCHAR(255) NOT NULL,"configuration_data" VARCHAR(16777216),"configuration_type" VARCHAR(255) NOT NULL,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP,"enabled" BOOLEAN DEFAULT TRUE NOT NULL) +CREATE MEMORY TABLE PUBLIC."restcomm_geolocation"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_executed" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"source" VARCHAR(30) NOT NULL,"device_identifier" VARCHAR(30) NOT NULL,"geolocation_type" VARCHAR(15) NOT NULL,"response_status" VARCHAR(30),"cell_id" VARCHAR(10),"location_area_code" VARCHAR(10),"mobile_country_code" INTEGER,"mobile_network_code" VARCHAR(3),"network_entity_address" BIGINT,"age_of_location_info" INTEGER,"device_latitude" VARCHAR(15),"device_longitude" VARCHAR(15),"accuracy" BIGINT,"physical_address" VARCHAR(50),"internet_address" VARCHAR(50),"formatted_address" VARCHAR(200),"location_timestamp" TIMESTAMP,"event_geofence_latitude" VARCHAR(15),"event_geofence_longitude" VARCHAR(15),"radius" BIGINT,"geolocation_positioning_type" VARCHAR(15),"last_geolocation_response" VARCHAR(10),"cause" VARCHAR(150),"api_version" VARCHAR(10) NOT NULL,"uri" VARCHAR(16777216) NOT NULL) +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 3 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC GRANT DBA TO SA -SET WRITE_DELAY 10 +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(2,2147483645,0) +INSERT INTO LOBS VALUES(0,1,0,1) +INSERT INTO LOBS VALUES(1,1,0,2) +INSERT INTO LOB_IDS VALUES(1,372,0,40) +INSERT INTO LOB_IDS VALUES(2,372,1,40) SET SCHEMA PUBLIC -INSERT INTO "restcomm_clients" VALUES('CL673db011517d40528a5e78ce8fbf07e5','2013-09-13 11:36:24.916000000','2013-09-13 11:36:24.916000000','ACa60def3495a345e99973aeca0976be0c','2012-04-24','Alice','alice','1234',1,'http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','AP2aa6d5236b704afeae960a222a481ea4','http://127.0.0.1:8080/restcomm/demos/hello-world.xml') -INSERT INTO "restcomm_registrations" VALUES('RG3378e1b361284af8a11fc610b23daa41','2013-09-11 22:11:56.969000000','2013-09-11 22:11:56.969000000','2013-09-11 22:11:56.969000000','sip:tom@company.com','Tom_2013-09-11T22:11:56.969+05:30','tom_2013-09-11T22:11:56.969+05:30',NULL,3600,'sip:tom@company.com') -INSERT INTO "restcomm_registrations" VALUES('RG393eee9214304c80a5a8381881fd8097','2013-09-11 22:11:57.143000000','2013-09-11 22:11:57.143000000','2013-09-11 22:11:57.143000000','sip:tom@company.com',NULL,'tom_2013-09-11T22:11:57.143+05:30','TestUserAgent/1.0',3600,'sip:tom@company.com') -INSERT INTO "restcomm_registrations" VALUES('RG6217b80f71e745cfb6d0c96973917979','2013-09-05 11:09:31.027000000','2013-09-05 11:09:31.027000000','2013-09-05 11:09:31.027000000','sip:tom@company.com','Tom_2013-09-05T11:09:31.027+03:00','tom_2013-09-05T11:09:31.027+03:00','TestUserAgent/1.0',3600,'sip:tom@company.com') -INSERT INTO "restcomm_registrations" VALUES('RGb88e1f5349b74c82b6eba9ea095a8653','2013-09-13 11:35:07.862000000','2013-09-13 11:35:07.862000000','2013-09-13 11:35:07.862000000','sip:tom@company.com','Tom_2013-09-13T11:35:07.862+03:00','tom_2013-09-13T11:35:07.862+03:00','TestUserAgent/1.0',3600,'sip:tom@company.com') -INSERT INTO "restcomm_registrations" VALUES('RGb8c6d068423b4b8ba5c705f25d2a5c83','2013-09-13 12:16:47.937000000','2013-09-13 12:16:47.937000000','2013-09-13 12:16:47.937000000','sip:tom@company.com','Tom_2013-09-13T12:16:47.937+03:00','tom_2013-09-13T12:16:47.937+03:00','TestUserAgent/1.0',3600,'sip:tom@company.com') +INSERT INTO "restcomm_organizations" VALUES('ORafbe225ad37541eba518a74248f0ac4c','default.restcomm.com','2017-04-19 00:00:00.000000','2017-04-19 00:00:00.000000', 'active') +INSERT INTO "restcomm_incoming_phone_numbers" VALUES('PN46678e5b01d44973bf184f6527bc33f7','2014-02-17 22:37:08.709000','2014-02-17 22:37:08.709000','This is an IVR app that maps user input to specific action','ACae6e420f425248d6a26948c17a9e2acf','+1240','2012-04-24',FALSE,NULL,'POST',NULL,'POST',NULL,'POST','AP00000000000000000000000000000000',NULL,'POST',NULL,'POST','AP11111111111111111111111111111111','/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PN46678e5b01d44973bf184f6527bc33f7',NULL,NULL,NULL,NULL,TRUE,'0.0',NULL,NULL,NULL,NULL,'AP22222222222222222222222222222222',NULL,NULL,NULL,NULL) +INSERT INTO "restcomm_applications" VALUES('AP00000000000000000000000000000000','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','app0','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','voice') +INSERT INTO "restcomm_applications" VALUES('AP11111111111111111111111111111111','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','app1','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','sms') +INSERT INTO "restcomm_applications" VALUES('AP22222222222222222222222222222222','2015-09-23 06:56:04.108000','2015-09-23 06:56:04.108000','app2','ACae6e420f425248d6a26948c17a9e2acf','2012-04-24',FALSE,'/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854','/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller','ussd') +INSERT INTO "restcomm_clients" VALUES('CL673db011517d40528a5e78ce8fbf07e5','2013-09-13 11:36:24.916000','2013-09-13 11:36:24.916000','ACa60def3495a345e99973aeca0976be0c','2012-04-24','Alice','alice','1234',1,'http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','AP2aa6d5236b704afeae960a222a481ea4','http://127.0.0.1:8080/restcomm/demos/hello-world.xml',NULL) +INSERT INTO "restcomm_clients" VALUES('CLf0785b3f1c5a422ea891170b620a7fa1','2017-08-08 10:43:35.228000','2017-08-08 10:43:35.228000','ACe2561dc77f744a7c8579f3f9946ccdeb','2012-04-24','Alice','alice','1234',1,'http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','http://127.0.0.1:8080/restcomm/demos/hello-world.xml','GET','APaf9e163ca396432a91350f398a7b9b8c','http://127.0.0.1:8080/restcomm/demos/hello-world.xml','CLf0785b3f1c5a422ea891170b620a7fa1') +INSERT INTO "restcomm_sms_messages" VALUES('SM07e9fd2c2ba144e083498b8b92309e32','2016-11-07 16:23:42.389000','2016-11-07 16:23:42.389000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM0d270a9eae514c2bacf57c7104b794a6','2016-11-07 16:25:22.982000','2016-11-07 16:25:22.982000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM0e5c641a3a9b47df9304d20e65980a94','2016-11-07 15:48:59.647000','2016-11-07 15:48:59.647000',NULL,'ACd51e5d69c0b243c2b7c33a3c9f09b47c','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM0efd04cc37cb48a1be5151f421ad6b73','2016-11-07 16:18:28.219000','2016-11-07 16:18:28.219000',NULL,'AC0f82c099f3e24b9cbc457874ffef42da','+17778889999','+12223334444','Hello World - 3','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM0f77ffdb92264e739bab438598cf80ca','2016-11-07 13:02:15.970000','2016-11-07 13:02:15.970000',NULL,'AC17665adc8f6d4f93abc7fe358bfe3ba9','+17778889999','+12223334444','Hello World - 3','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM0fb49681d37d4e5e839015c6c9f4fe68','2016-11-07 13:01:17.786000','2016-11-07 13:01:17.786000',NULL,'AC40beb7ea1ee54eacad9688ebd0927222','+17778889999','+12223334444','Hello World - 4','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM11ac1412f5de43c4baee7fa1169c6e4b','2016-11-07 16:06:38.165000','2016-11-07 16:06:38.165000',NULL,'AC7b9558da76e84faf866f4907ac140904','+17778889999','+12223334444','Hello World - 3','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM122690ae371a4c579ccb5bd9176e34bc','2016-11-07 16:29:11.166000','2016-11-07 16:29:11.166000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM1dd15c7980cc4801a0741d5ddaf2264c','2016-11-07 16:18:28.212000','2016-11-07 16:18:28.212000',NULL,'AC0f82c099f3e24b9cbc457874ffef42da','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM1fcd519a281b4cbbaf7a6641925e723f','2016-11-07 16:21:09.734000','2016-11-07 16:21:09.734000',NULL,'AC959ca898f0c74b6fb01715b13d307606','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM256436ab49164917bc1cf301b4f26711','2016-11-23 10:42:18.196000','2016-11-23 10:42:18.196000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM2d486355a0414830be66771efcf908f6','2016-11-23 10:42:18.187000','2016-11-23 10:42:18.187000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM2f528e58d3c04d78a7d6079e9bde2c46','2016-11-07 16:25:22.975000','2016-11-07 16:25:22.975000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM30e7eab62549442f88663471c339215a','2016-11-07 16:30:41.175000','2016-11-07 16:30:41.175000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM321b7b751fea44b6b4178231ee6e6f3b','2016-11-07 16:32:11.947000','2016-11-07 16:32:11.947000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM33696bf2b3cf4efe9bcbdc523a113b32','2016-11-07 16:30:41.169000','2016-11-07 16:30:41.169000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM35b311996f504f1191f82fb54c1fadb1','2016-11-07 13:02:15.963000','2016-11-07 13:02:15.963000',NULL,'AC17665adc8f6d4f93abc7fe358bfe3ba9','+17778889999','+12223334444','Hello World - 1','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM3f251e8f63324a33b86dd29508313781','2016-11-07 16:18:27.669000','2016-11-07 16:18:27.669000',NULL,'AC0f82c099f3e24b9cbc457874ffef42da','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM44a844a9e6cd477d8a66466f90f25c6b','2016-11-07 16:21:10.229000','2016-11-07 16:21:10.229000',NULL,'AC959ca898f0c74b6fb01715b13d307606','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM46662566cca44799a607b0d80c65e237','2016-11-07 13:28:58.797000','2016-11-07 13:28:58.797000',NULL,'AC83cab7e5b6494a4cb62808c58d371e4b','+17778889999','+12223334444','Hello World - 3','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM47912faee136445baea6bec88093c8b3','2016-11-07 15:48:59.160000','2016-11-07 15:48:59.160000',NULL,'ACd51e5d69c0b243c2b7c33a3c9f09b47c','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM4e1e1ee41cab4e33a68d027a216e236b','2016-11-07 13:28:58.802000','2016-11-07 13:28:58.802000',NULL,'AC83cab7e5b6494a4cb62808c58d371e4b','+17778889999','+12223334444','Hello World - 4','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM4eb59776c3c84b3ea6a4bd309ef6531c','2016-11-07 16:29:11.752000','2016-11-07 16:29:11.752000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM59b69869848c4b678b49ba56b2a82ac0','2016-11-07 16:29:11.749000','2016-11-07 16:29:11.749000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM59efa803fdd44565b843b97790193b1c','2016-11-07 16:06:38.159000','2016-11-07 16:06:38.159000',NULL,'AC7b9558da76e84faf866f4907ac140904','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM5a0d35ff2cc04232801a32d61b918630','2016-11-07 15:48:59.651000','2016-11-07 15:48:59.651000',NULL,'ACd51e5d69c0b243c2b7c33a3c9f09b47c','+17778889999','+12223334444','Hello World - 2','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM5a0f0c669fd746f69e3b69de45cbdefa','2016-11-23 10:42:18.180000','2016-11-23 10:42:18.180000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM5b45e539b907462e92b49223d9734d6c','2016-11-07 12:56:20.904000','2016-11-07 12:56:20.904000',NULL,'ACc35cbfac92434756930fd864bb50d1b8','+17778889999','+12223334444','Hello World - 1','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM5b886e140cec4370a7ed0d1a72606dc4','2016-11-07 16:23:42.383000','2016-11-07 16:23:42.383000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM5eb40b34a7af421aa70242c94292f995','2016-11-07 16:23:42.375000','2016-11-07 16:23:42.375000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM63771ee9e0894bf0886abf627226406c','2016-11-07 16:25:22.988000','2016-11-07 16:25:22.988000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM661374cf0bf342a4b5c005bb91e36e6d','2016-11-07 16:25:22.979000','2016-11-07 16:25:22.979000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM6ab3a3dfe16e4686b8326b1d1c0353db','2016-11-07 16:30:40.673000','2016-11-07 16:30:40.673000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM707cecf9bbe443af90d811889a9f8e40','2016-11-07 13:01:17.287000','2016-11-07 13:01:17.287000',NULL,'AC40beb7ea1ee54eacad9688ebd0927222','+17778889999','+12223334444','Hello World - 0','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM7258d2c107eb4f6ba4990a55c2b45fe1','2016-11-07 16:18:28.222000','2016-11-07 16:18:28.222000',NULL,'AC0f82c099f3e24b9cbc457874ffef42da','+17778889999','+12223334444','Hello World - 4','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM73b95e001b2745afa9b4f3662d34571d','2016-11-07 16:32:11.958000','2016-11-07 16:32:11.958000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM76e81d2b2fb143ccb96cefc78dedd30a','2016-11-07 16:30:41.172000','2016-11-07 16:30:41.172000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM7afeea91730a49ba8e68aa35f804bfec','2016-11-07 12:56:20.911000','2016-11-07 12:56:20.911000',NULL,'ACc35cbfac92434756930fd864bb50d1b8','+17778889999','+12223334444','Hello World - 3','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM8046a3be1e934a7aa3f9218bfe2320e3','2016-11-07 16:23:42.386000','2016-11-07 16:23:42.386000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM81e8e021c84a4532a1a1e12bfbb56ec9','2016-11-07 13:01:17.783000','2016-11-07 13:01:17.783000',NULL,'AC40beb7ea1ee54eacad9688ebd0927222','+17778889999','+12223334444','Hello World - 3','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM86270c0b7a634e6c990478e31c6a1528','2016-11-07 13:01:17.779000','2016-11-07 13:01:17.779000',NULL,'AC40beb7ea1ee54eacad9688ebd0927222','+17778889999','+12223334444','Hello World - 2','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM869cf983304749ba922d328ace842caf','2016-11-07 16:06:37.600000','2016-11-07 16:06:37.600000',NULL,'AC7b9558da76e84faf866f4907ac140904','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM86eb5650bf9148549e333f336d8156d2','2016-11-07 16:25:22.985000','2016-11-07 16:25:22.985000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM8891c8dffb15402c9a27791a76a46c0c','2016-11-07 16:29:11.755000','2016-11-07 16:29:11.755000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM8f0e902389bc4cbaa84e8318bd01a6a7','2016-11-07 13:02:15.973000','2016-11-07 13:02:15.973000',NULL,'AC17665adc8f6d4f93abc7fe358bfe3ba9','+17778889999','+12223334444','Hello World - 4','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM91b74d9df65e401e9eeeb1ffc3ddd8b2','2017-03-10 14:12:41.027000','2017-03-10 14:12:41.027000',NULL,'AC1af7c7f865e848b8bf51cf79d8d23366','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM9475aaa323754ffdac0b6f8f9b64b606','2016-11-07 15:43:05.938000','2016-11-07 15:43:05.938000',NULL,'ACa588c8c5c23140eab67a347f0d084747','+17778889999','+12223334444','Hello World - 3','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM96a0c773bf4642a5b0182ff5de1d855b','2016-11-23 10:42:18.193000','2016-11-23 10:42:18.193000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM975afd2524c84cf18d2fc181219601f4','2016-11-07 15:48:59.654000','2016-11-07 15:48:59.654000',NULL,'ACd51e5d69c0b243c2b7c33a3c9f09b47c','+17778889999','+12223334444','Hello World - 3','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM9c3b2eeed6bb476b8df347b75186fe9f','2016-11-07 13:28:58.251000','2016-11-07 13:28:58.251000',NULL,'AC83cab7e5b6494a4cb62808c58d371e4b','+17778889999','+12223334444','Hello World - 0','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM9c48b014c26443589030bbfda0e0047e','2016-11-07 16:21:10.236000','2016-11-07 16:21:10.236000',NULL,'AC959ca898f0c74b6fb01715b13d307606','+17778889999','+12223334444','Hello World - 3','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SM9de9ac3d119641c190feaeccf99988a4','2016-11-07 12:56:20.908000','2016-11-07 12:56:20.908000',NULL,'ACc35cbfac92434756930fd864bb50d1b8','+17778889999','+12223334444','Hello World - 2','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMa145d352c1484385b2713980caa1f5a0','2016-11-07 13:01:17.775000','2016-11-07 13:01:17.775000',NULL,'AC40beb7ea1ee54eacad9688ebd0927222','+17778889999','+12223334444','Hello World - 1','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMa8a5131252f84092bf717eb076a08a86','2016-11-07 16:29:11.745000','2016-11-07 16:29:11.745000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMaa8d00be20f14c059676fc22f5f4aa0c','2016-11-07 16:23:42.380000','2016-11-07 16:23:42.380000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMab6693545f8445438ac619f966939174','2016-11-07 16:32:11.950000','2016-11-07 16:32:11.950000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMaccb50c05c314274b7db77c0e33d0aff','2016-11-07 15:43:05.941000','2016-11-07 15:43:05.941000',NULL,'ACa588c8c5c23140eab67a347f0d084747','+17778889999','+12223334444','Hello World - 4','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMb30ef7ec5820460ca14ff47e3aabc42c','2016-11-07 16:06:38.162000','2016-11-07 16:06:38.162000',NULL,'AC7b9558da76e84faf866f4907ac140904','+17778889999','+12223334444','Hello World - 2','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMb3bbfe0e5a3b47c484e75f8ae9514e52','2016-11-07 16:32:11.953000','2016-11-07 16:32:11.953000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMb6ccecc2d9e24ad193447e3f3a17493a','2016-11-07 13:02:15.967000','2016-11-07 13:02:15.967000',NULL,'AC17665adc8f6d4f93abc7fe358bfe3ba9','+17778889999','+12223334444','Hello World - 2','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMb855e151df0f404e8594a4ba0f4d8521','2016-11-07 16:18:28.215000','2016-11-07 16:18:28.215000',NULL,'AC0f82c099f3e24b9cbc457874ffef42da','+17778889999','+12223334444','Hello World - 2','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMba1919724958468d9879108cef8ab317','2016-11-07 16:25:22.441000','2016-11-07 16:25:22.441000',NULL,'ACca736f43d70241e8822158b02ce6cb2a','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMbb61b91ed8ec4787bae1516a900bb637','2016-11-07 15:43:05.934000','2016-11-07 15:43:05.934000',NULL,'ACa588c8c5c23140eab67a347f0d084747','+17778889999','+12223334444','Hello World - 2','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMc315218a2ffc4199862dff1131260276','2016-11-07 16:21:10.239000','2016-11-07 16:21:10.239000',NULL,'AC959ca898f0c74b6fb01715b13d307606','+17778889999','+12223334444','Hello World - 4','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMc3d25967dcd24af08642d66ee8ba2a78','2016-11-07 16:21:10.233000','2016-11-07 16:21:10.233000',NULL,'AC959ca898f0c74b6fb01715b13d307606','+17778889999','+12223334444','Hello World - 2','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMc541148679b4448ea0592f7d88730548','2016-11-07 16:06:38.169000','2016-11-07 16:06:38.169000',NULL,'AC7b9558da76e84faf866f4907ac140904','+17778889999','+12223334444','Hello World - 4','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMcc8649c04eaa404ba0ff989a877c959d','2016-11-07 15:43:05.426000','2016-11-07 15:43:05.426000',NULL,'ACa588c8c5c23140eab67a347f0d084747','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMce80cd405a7d42da8724ed5ce21ad87c','2016-11-23 10:42:18.190000','2016-11-23 10:42:18.190000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 1','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMcf2aa4e813fd45788a28d9fc81a345a6','2016-11-07 13:28:58.784000','2016-11-07 13:28:58.784000',NULL,'AC83cab7e5b6494a4cb62808c58d371e4b','+17778889999','+12223334444','Hello World - 1','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMcfe5b35c626c47138002b7e0d63e8d18','2016-11-07 16:23:41.882000','2016-11-07 16:23:41.882000',NULL,'AC681caba993db40fd9166404f6a30e67d','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMd126aa4516bb4d30b2e3e4f008e99875','2016-11-07 13:28:58.789000','2016-11-07 13:28:58.789000',NULL,'AC83cab7e5b6494a4cb62808c58d371e4b','+17778889999','+12223334444','Hello World - 2','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMdea2ae7b33984f5099c92fac6a6b2983','2016-11-07 16:32:11.943000','2016-11-07 16:32:11.943000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 0','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMdf4e28f9074a4de19a8056afdfbd3a6f','2016-11-07 16:29:11.741000','2016-11-07 16:29:11.741000',NULL,'AC129c7b8b593545088c6ce44edb617575','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMe8a44267f8114e25863a2ce7885fa50c','2017-03-10 14:12:41.665000','2017-03-10 14:12:41.665000',NULL,'AC1af7c7f865e848b8bf51cf79d8d23366','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMec3d1e365fe4411a9023f47166398d86','2016-11-07 13:02:15.494000','2016-11-07 13:02:15.494000',NULL,'AC17665adc8f6d4f93abc7fe358bfe3ba9','+17778889999','+12223334444','Hello World - 0','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMed93614bf8b443cf9e4e5deb69679a01','2016-11-07 16:30:41.163000','2016-11-07 16:30:41.163000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf2631ca6c906460d840a779fbfc5f181','2016-11-07 12:56:20.915000','2016-11-07 12:56:20.915000',NULL,'ACc35cbfac92434756930fd864bb50d1b8','+17778889999','+12223334444','Hello World - 4','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf348a718ffef476bb910dc6652d8ead4','2016-11-07 16:32:11.955000','2016-11-07 16:32:11.955000',NULL,'ACe58a0a23242c45da84d394643dc201fe','+17778889999','+12223334444','Hello World - 0','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf7df85a9a7554b02953523b0f5be3516','2016-11-07 12:56:20.367000','2016-11-07 12:56:20.367000',NULL,'ACc35cbfac92434756930fd864bb50d1b8','+17778889999','+12223334444','Hello World - 0','sending','inbound','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf842e57f49134dcc93833c165e2a9723','2016-11-07 16:30:41.166000','2016-11-07 16:30:41.166000',NULL,'ACeff57c26f83446bcbe68083641c20a11','+17778889999','+12223334444','Hello World - 0','sending','outbound-call','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf8c8c4471ca840f69380f700559b9cbc','2016-11-07 15:48:59.657000','2016-11-07 15:48:59.657000',NULL,'ACd51e5d69c0b243c2b7c33a3c9f09b47c','+17778889999','+12223334444','Hello World - 4','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMf8dcc0ab305f4c9282fee7628dd8ad23','2016-11-23 10:42:18.184000','2016-11-23 10:42:18.184000',NULL,'AC2290be3e337c42baa8a38bf04b0e971c','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMfdff370f64984ef1aeb757a2403ccc55','2017-03-10 14:12:41.695000','2017-03-10 14:12:41.695000',NULL,'AC1af7c7f865e848b8bf51cf79d8d23366','+17778889999','+12223334444','Hello World - 1','sending','outbound-reply','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_sms_messages" VALUES('SMfe52613b53494cf193b3cae1ba05cd25','2016-11-07 15:43:05.930000','2016-11-07 15:43:05.930000',NULL,'ACa588c8c5c23140eab67a347f0d084747','+17778889999','+12223334444','Hello World - 1','sending','outbound-api','0.00','2012-04-24','2012-04-24/Accounts/Acoount/SMS/Messages/unique-id.json') +INSERT INTO "restcomm_recordings" VALUES('RE08ff2d059d644819a99a92fa69b73ea3','2017-04-05 12:58:10.950000','2017-04-05 12:58:10.999000','AC0da06c6452ae4af8b23264408b86e9ed','CAd7d0ad61f24542b6ba095ac967213392',3.0E0,'2012-04-24','/2012-04-24/Accounts/AC9cbb219fb1fe7400ef365a38b282b286/Recordings/RE7ddbd5b441574e4ab786a1fddf33eb47','/restcomm/2012-04-24/Accounts/AC0da06c6452ae4af8b23264408b86e9ed/Recordings/RE08ff2d059d644819a99a92fa69b73ea3.wav') +INSERT INTO "restcomm_recordings" VALUES('RE7a2345a37a2a4f18a2a715e8f352c4ed','2017-04-05 12:57:35.535000','2017-04-05 12:57:35.583000','ACe4462e9eb95b4cf8ae17001ab2f520af','CA2d3f6354e75e46b3ac76f534129ff511',3.0E0,'2012-04-24','/2012-04-24/Accounts/AC9cbb219fb1fe7400ef365a38b282b286/Recordings/RE7ddbd5b441574e4ab786a1fddf33eb47','/restcomm/2012-04-24/Accounts/ACe4462e9eb95b4cf8ae17001ab2f520af/Recordings/RE7a2345a37a2a4f18a2a715e8f352c4ed.wav') diff --git a/restcomm/restcomm.dao/src/test/resources/incoming-phone-numbers.xml b/restcomm/restcomm.dao/src/test/resources/incoming-phone-numbers.xml deleted file mode 100644 index 6a7185df8c..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/incoming-phone-numbers.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - INSERT INTO "restcomm_incoming_phone_numbers" ("sid", "date_created", "date_updated", "friendly_name", "account_sid", "phone_number", "api_version", - "voice_caller_id_lookup", "voice_url", "voice_method", "voice_fallback_url", "voice_fallback_method", "status_callback", "status_callback_method", - "voice_application_sid", "sms_url", "sms_method", "sms_fallback_url", "sms_fallback_method", "sms_application_sid", "uri") VALUES(#{sid}, - #{date_created}, #{date_updated}, #{friendly_name}, #{account_sid}, #{phone_number}, #{api_version}, #{voice_caller_id_lookup}, - #{voice_url}, #{voice_method}, #{voice_fallback_url}, #{voice_fallback_method}, #{status_callback}, #{status_callback_method}, - #{voice_application_sid}, #{sms_url}, #{sms_method}, #{sms_fallback_url}, #{sms_fallback_method}, #{sms_application_sid}, #{uri}); - - - - - - - - - - - - DELETE FROM "restcomm_incoming_phone_numbers" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_incoming_phone_numbers" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_incoming_phone_numbers" SET "friendly_name"=#{friendly_name}, "voice_caller_id_lookup"=#{voice_caller_id_lookup}, "voice_url"=#{voice_url}, - "voice_method"=#{voice_method}, "voice_fallback_url"=#{voice_fallback_url}, "voice_fallback_method"=#{voice_fallback_method}, "status_callback"=#{status_callback}, - "status_callback_method"=#{status_callback_method}, "voice_application_sid"=#{voice_application_sid}, "sms_url"=#{sms_url}, "sms_method"=#{sms_method}, - "sms_fallback_url"=#{sms_fallback_url}, "sms_fallback_method"=#{sms_fallback_method}, "sms_application_sid"=#{sms_application_sid} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/log4j.xml b/restcomm/restcomm.dao/src/test/resources/log4j.xml new file mode 100644 index 0000000000..b3677225e2 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/log4j.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/mybatis.xml b/restcomm/restcomm.dao/src/test/resources/mybatis.xml index 8ec9843691..5addd23a20 100644 --- a/restcomm/restcomm.dao/src/test/resources/mybatis.xml +++ b/restcomm/restcomm.dao/src/test/resources/mybatis.xml @@ -9,7 +9,8 @@ - + + @@ -18,22 +19,26 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/mybatis_pertest.xml b/restcomm/restcomm.dao/src/test/resources/mybatis_pertest.xml new file mode 100644 index 0000000000..b4cb62979b --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/mybatis_pertest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/notifications.xml b/restcomm/restcomm.dao/src/test/resources/notifications.xml deleted file mode 100644 index b4f814a7c6..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/notifications.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - INSERT INTO "restcomm_notifications" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "api_version", "log", "error_code", "more_info", "message_text", - "message_date", "request_url", "request_method", "request_variables", "response_headers", "response_body", "uri") VALUES (#{sid}, #{date_created}, #{date_updated}, - #{account_sid}, #{call_sid}, #{api_version}, #{log}, #{error_code}, #{more_info}, #{message_text}, #{message_date}, #{request_url}, #{request_method}, - #{request_variables}, #{response_headers}, #{response_body}, #{uri}); - - - - - - - - - - - - - - DELETE FROM "restcomm_notifications" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_notifications" WHERE "account_sid"=#{account_sid}; - - - - DELETE FROM "restcomm_notifications" WHERE "call_sid"=#{call_sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/organizationsDao/mybatis.xml b/restcomm/restcomm.dao/src/test/resources/organizationsDao/mybatis.xml new file mode 100644 index 0000000000..b22e6ae408 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/organizationsDao/mybatis.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/organizationsDao/organization.xml b/restcomm/restcomm.dao/src/test/resources/organizationsDao/organization.xml new file mode 100644 index 0000000000..15d6a3a4b1 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/organizationsDao/organization.xml @@ -0,0 +1,31 @@ + + + + + + INSERT INTO "restcomm_organizations" ("sid", "domain_name", "date_created", "date_updated", "status") + VALUES(#{sid}, #{domain_name}, #{date_created}, #{date_updated}, #{status}); + + + + + + + + + + + + UPDATE "restcomm_organizations" SET "date_updated"=#{date_updated}, + "domain_name"=#{domain_name} + WHERE "sid"=#{sid}; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile-association.xml b/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile-association.xml new file mode 100644 index 0000000000..3b0adf8977 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile-association.xml @@ -0,0 +1,46 @@ + + + + + + INSERT INTO "restcomm_profile_associations" ("profile_sid", "target_sid", "date_created", "date_updated") + VALUES(#{profile_sid}, #{target_sid}, #{date_created}, #{date_updated}); + + + + + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "target_sid"=#{target_sid}; + + + + UPDATE "restcomm_profile_associations" SET "date_updated"=NOW(), + "profile_sid"=#{profile_sid} + WHERE "profile_sid"=#{old_profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE "profile_sid"=#{profile_sid}; + + + + DELETE from "restcomm_profile_associations" + WHERE '1' = '1' + + AND "target_sid" = #{target_sid} + + + AND "profile_sid" = #{profile_sid} + + ; + + \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile.xml b/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile.xml new file mode 100644 index 0000000000..b8a9c8a9df --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/organizationsDao/profile.xml @@ -0,0 +1,28 @@ + + + + + + INSERT INTO "restcomm_profiles" ("sid", "document", "date_created", "date_updated") + VALUES(#{sid, jdbcType=VARCHAR}, #{profileDocument, jdbcType=LONGVARCHAR}, #{dateCreated, jdbcType=TIMESTAMP}, #{dateUpdated, jdbcType=TIMESTAMP}); + + + + + + + + UPDATE "restcomm_profiles" SET "date_updated"=#{dateUpdated, jdbcType=TIMESTAMP}, + "document"=#{profileDocument, jdbcType=LONGVARCHAR} + WHERE "sid"=#{sid, jdbcType=VARCHAR}; + + + + DELETE from "restcomm_profiles" + WHERE "sid"=#{sid, jdbcType=VARCHAR}; + + diff --git a/restcomm/restcomm.dao/src/test/resources/organizationsDao/restcomm.script b/restcomm/restcomm.dao/src/test/resources/organizationsDao/restcomm.script new file mode 100644 index 0000000000..dc3d953823 --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/organizationsDao/restcomm.script @@ -0,0 +1,58 @@ +SET DATABASE UNIQUE NAME HSQLDB4B9865B1C6 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE FALSE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 10 +SET FILES BACKUP INCREMENT FALSE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 1 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 200 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +SET SCHEMA PUBLIC +CREATE MEMORY TABLE "restcomm_profile_associations"("target_sid" LONGVARCHAR NOT NULL PRIMARY KEY, "profile_sid" LONGVARCHAR NOT NULL, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL) +CREATE MEMORY TABLE "restcomm_organizations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "domain_name" VARCHAR(255) NOT NULL UNIQUE, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "status" VARCHAR(16)) +CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL, "organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') +CREATE MEMORY TABLE "restcomm_profiles"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "document" LONGVARCHAR NOT NULL, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL) +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) +SET SCHEMA PUBLIC +INSERT INTO "restcomm_organizations" VALUES('ORafbe225ad37541eba518a74248f0ac4c', 'default.restcomm.com', '2017-04-19 00:00:00.000000000','2017-04-19 00:00:00.000000000', 'active') +INSERT INTO "restcomm_organizations" VALUES('ORafbe225ad37541eba518a74248f0ac4d', 'test2.restcomm.com.', '2017-04-19 00:00:00.000000000','2017-04-19 00:00:00.000000000', 'active') +INSERT INTO "restcomm_accounts" VALUES('AC00000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','administrator@company.com','Top Level Account',NULL,'Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC00000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC10000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child1@company.com','Child 1','AC00000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC10000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC20000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child2@company.com','Child 2','AC00000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC20000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC11000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child11@company.com','Child 1-1','AC10000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC11000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC12000000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child12@company.com','Child 1-2','AC10000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC12000000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC11100000000000000000000000000000','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','child111@company.com','Child 1-1-1','AC11000000000000000000000000000000','Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC11100000000000000000000000000000','ORafbe225ad37541eba518a74248f0ac4c') +INSERT INTO "restcomm_accounts" VALUES('AC99999999999999999999999999999999','2012-04-24 00:00:00.000000000','2012-04-24 00:00:00.000000000','lonelyparent@company.com','Lonely Parent',NULL,'Full','active','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/AC99999999999999999999999999999999','ORafbe225ad37541eba518a74248f0ac4c') diff --git a/restcomm/restcomm.dao/src/test/resources/recordings.xml b/restcomm/restcomm.dao/src/test/resources/recordings.xml deleted file mode 100644 index eb7ea28130..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/recordings.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - INSERT INTO "restcomm_recordings" ("sid", "date_created", "date_updated", "account_sid", "call_sid", "duration", "api_version", "uri") - VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{call_sid}, #{duration}, #{api_version}, #{uri}); - - - - - - - - - - DELETE FROM "restcomm_recordings" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_recordings" WHERE "account_sid"=#{account_sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/registrations.xml b/restcomm/restcomm.dao/src/test/resources/registrations.xml deleted file mode 100644 index 6227be73d2..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/registrations.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - INSERT INTO "restcomm_registrations" ("sid", "date_created", "date_updated", "date_expires", "address_of_record", "display_name", - "user_name", "user_agent", "ttl", "location") - VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_expires}, #{address_of_record}, #{display_name}, #{user_name}, #{user_agent}, - #{ttl}, #{location}); - - - - - - - - - - DELETE FROM "restcomm_registrations" WHERE "location"=#{location} AND "address_of_record"=#{address_of_record}; - - - - UPDATE "restcomm_registrations" SET "ttl"=#{ttl}, "date_expires"=#{date_expires} WHERE "address_of_record"=#{address_of_record} AND - "display_name"=#{display_name} AND "location"=#{location} AND "user_agent"=#{user_agent}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/restcomm.script b/restcomm/restcomm.dao/src/test/resources/restcomm.script index 7e1dd30fdf..024c379c66 100644 --- a/restcomm/restcomm.dao/src/test/resources/restcomm.script +++ b/restcomm/restcomm.dao/src/test/resources/restcomm.script @@ -1,21 +1,27 @@ CREATE SCHEMA PUBLIC AUTHORIZATION DBA -CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_announcements"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34),"gender" VARCHAR(8) NOT NULL,"language" VARCHAR(16) NOT NULL,"text" VARCHAR(32) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL) -CREATE MEMORY TABLE "restcomm_outgoing_caller_ids"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_http_cookies"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"comment" LONGVARCHAR,"domain" LONGVARCHAR,"expiration_date" TIMESTAMP,"name" LONGVARCHAR NOT NULL,"path" LONGVARCHAR,"value" LONGVARCHAR,"version" INTEGER) -CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_caller_id_lookup" BOOLEAN NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_status_callback" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(34),"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(11) NOT NULL,"start_time" TIMESTAMP,"end_time" TIMESTAMP,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(13) NOT NULL,"answered_by" VARCHAR(7),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(15),"caller_name" VARCHAR(30),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_expires" TIMESTAMP NOT NULL,"address_of_record" LONGVARCHAR NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" LONGVARCHAR,"ttl" INTEGER NOT NULL,"location" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_short_codes"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"short_code" INTEGER NOT NULL,"api_version" VARCHAR(10) NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"date_sent" TIMESTAMP,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(15) NOT NULL,"body" VARCHAR(160) NOT NULL,"status" VARCHAR(7) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_transcriptions"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(11) NOT NULL,"recording_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"transcription_text" LONGVARCHAR NOT NULL,"price" VARCHAR(8) NOT NULL,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(34),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" LONGVARCHAR NOT NULL,"message_text" LONGVARCHAR NOT NULL,"message_date" TIMESTAMP NOT NULL,"request_url" LONGVARCHAR NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" LONGVARCHAR NOT NULL,"response_headers" LONGVARCHAR,"response_body" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_sand_boxes"("date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"pin" VARCHAR(8) NOT NULL,"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY,"phone_number" VARCHAR(15) NOT NULL,"application_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) -CREATE MEMORY TABLE "restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP NOT NULL,"friendly_name" VARCHAR(255),"user_name" VARCHAR(255),"password" VARCHAR(255),"proxy" LONGVARCHAR NOT NULL,"register" BOOLEAN NOT NULL,"ttl" INTEGER NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_instance_id"("instance_id" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL, "host" VARCHAR(255) NOT NULL) +CREATE MEMORY TABLE "restcomm_accounts"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"email_address" LONGVARCHAR NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"parent_sid" VARCHAR(34),"type" VARCHAR(8) NOT NULL,"status" VARCHAR(16) NOT NULL,"auth_token" VARCHAR(32) NOT NULL,"role" VARCHAR(64) NOT NULL,"uri" LONGVARCHAR NOT NULL, "organization_sid" VARCHAR(34) DEFAULT 'ORafbe225ad37541eba518a74248f0ac4c') +CREATE MEMORY TABLE "restcomm_announcements"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"account_sid" VARCHAR(34),"gender" VARCHAR(8) NOT NULL,"language" VARCHAR(16) NOT NULL,"text" VARCHAR(32) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_available_phone_numbers"("friendly_name" VARCHAR(64) NOT NULL,"phone_number" VARCHAR(15) NOT NULL PRIMARY KEY,"lata" SMALLINT,"rate_center" VARCHAR(32),"latitude" DOUBLE,"longitude" DOUBLE,"region" VARCHAR(2),"postal_code" INTEGER,"iso_country" VARCHAR(2) NOT NULL,"voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN,"cost" VARCHAR(10)) +CREATE MEMORY TABLE "restcomm_outgoing_caller_ids"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(15) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_http_cookies"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"comment" LONGVARCHAR,"domain" LONGVARCHAR,"expiration_date" DATETIME,"name" LONGVARCHAR NOT NULL,"path" LONGVARCHAR,"value" LONGVARCHAR,"version" INT) +CREATE MEMORY TABLE "restcomm_incoming_phone_numbers"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"phone_number" VARCHAR(30) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"sms_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "voice_capable" BOOLEAN, "sms_capable" BOOLEAN, "mms_capable" BOOLEAN, "fax_capable" BOOLEAN, "pure_sip" BOOLEAN,"cost" VARCHAR(10), "ussd_url" LONGVARCHAR, "ussd_method" VARCHAR(4), "ussd_fallback_url" LONGVARCHAR, "ussd_fallback_method" VARCHAR(4), "ussd_application_sid" VARCHAR(34), "refer_url" LONGVARCHAR, "refer_method" VARCHAR(4), "refer_application_sid" VARCHAR(34), "organization_sid" VARCHAR(34) NOT NULL) +CREATE MEMORY TABLE "restcomm_applications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_caller_id_lookup" BOOLEAN NOT NULL,"uri" LONGVARCHAR NOT NULL,"rcml_url" LONGVARCHAR, "kind" VARCHAR(5)) +CREATE MEMORY TABLE "restcomm_call_detail_records"("sid" VARCHAR(1000) NOT NULL PRIMARY KEY,"parent_call_sid" VARCHAR(1000),"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(30) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"phone_number_sid" VARCHAR(34),"status" VARCHAR(20) NOT NULL,"start_time" DATETIME,"end_time" DATETIME,"duration" INTEGER,"price" VARCHAR(8),"direction" VARCHAR(20) NOT NULL,"answered_by" VARCHAR(64),"api_version" VARCHAR(10) NOT NULL,"forwarded_from" VARCHAR(30),"caller_name" VARCHAR(50),"uri" LONGVARCHAR NOT NULL, "call_path" VARCHAR(255),"ring_duration" INTEGER, "instanceid" VARCHAR(255) NOT NULL, "conference_sid" VARCHAR(34),"muted" BOOLEAN, "start_conference_on_enter" BOOLEAN, "end_conference_on_exit" BOOLEAN, "on_hold" BOOLEAN, "ms_id" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_conference_detail_records" ( "sid" VARCHAR(34) NOT NULL PRIMARY KEY, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "account_sid" VARCHAR(34) NOT NULL, "status" VARCHAR(100) NOT NULL, "friendly_name" VARCHAR(60), "api_version" VARCHAR(10) NOT NULL, "uri" LONGVARCHAR NOT NULL, "master_ms_id" VARCHAR(34),"master_conference_endpoint_id" VARCHAR(20),"master_present" BOOLEAN DEFAULT TRUE, "master_ivr_endpoint_id" VARCHAR(20),"master_ivr_endpoint_session_id" VARCHAR(200),"master_bridge_endpoint_id" VARCHAR(20),"master_bridge_endpoint_session_id" VARCHAR(200),"master_bridge_conn_id" VARCHAR(200),"master_ivr_conn_id" VARCHAR(200)) +CREATE MEMORY TABLE "restcomm_clients"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"login" VARCHAR(64) NOT NULL,"password" VARCHAR(64) NOT NULL,"status" INTEGER NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"voice_fallback_url" LONGVARCHAR,"voice_fallback_method" VARCHAR(4),"voice_application_sid" VARCHAR(34),"uri" LONGVARCHAR NOT NULL, "push_client_identity" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_registrations"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_expires" DATETIME NOT NULL,"address_of_record" LONGVARCHAR NOT NULL,"display_name" VARCHAR(255),"user_name" VARCHAR(64) NOT NULL,"user_agent" LONGVARCHAR,"ttl" INTEGER NOT NULL,"location" LONGVARCHAR NOT NULL, "webrtc" BOOLEAN DEFAULT FALSE, "instanceid" VARCHAR(255), "isLBPresent" BOOLEAN DEFAULT FALSE, "organization_sid" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_short_codes"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(64) NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"short_code" INTEGER NOT NULL,"api_version" VARCHAR(10) NOT NULL,"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"sms_fallback_url" LONGVARCHAR,"sms_fallback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_sms_messages"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"date_sent" DATETIME,"account_sid" VARCHAR(34) NOT NULL,"sender" VARCHAR(15) NOT NULL,"recipient" VARCHAR(64) NOT NULL,"body" VARCHAR(999) NOT NULL,"status" VARCHAR(20) NOT NULL,"direction" VARCHAR(14) NOT NULL,"price" VARCHAR(8) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_recordings"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000) NOT NULL,"duration" DOUBLE NOT NULL,"api_version" VARCHAR(10) NOT NULL,"uri" LONGVARCHAR NOT NULL, "file_uri" LONGVARCHAR) +CREATE MEMORY TABLE "restcomm_transcriptions"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"status" VARCHAR(11) NOT NULL,"recording_sid" VARCHAR(34) NOT NULL,"duration" DOUBLE NOT NULL,"transcription_text" LONGVARCHAR,"price" VARCHAR(8) NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_notifications"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"account_sid" VARCHAR(34) NOT NULL,"call_sid" VARCHAR(1000),"api_version" VARCHAR(10) NOT NULL,"log" TINYINT NOT NULL,"error_code" SMALLINT NOT NULL,"more_info" LONGVARCHAR NOT NULL,"message_text" LONGVARCHAR NOT NULL,"message_date" DATETIME NOT NULL,"request_url" LONGVARCHAR NOT NULL,"request_method" VARCHAR(4) NOT NULL,"request_variables" LONGVARCHAR NOT NULL,"response_headers" LONGVARCHAR,"response_body" LONGVARCHAR,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_sand_boxes"("date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"pin" VARCHAR(8) NOT NULL,"account_sid" VARCHAR(34) NOT NULL PRIMARY KEY,"phone_number" VARCHAR(15) NOT NULL,"application_sid" VARCHAR(34) NOT NULL,"api_version" VARCHAR(10) NOT NULL,"voice_url" LONGVARCHAR,"voice_method" VARCHAR(4),"sms_url" LONGVARCHAR,"sms_method" VARCHAR(4),"status_callback" LONGVARCHAR,"status_callback_method" VARCHAR(4),"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"date_created" DATETIME NOT NULL,"date_updated" DATETIME NOT NULL,"friendly_name" VARCHAR(255),"user_name" VARCHAR(255),"password" VARCHAR(255),"proxy" LONGVARCHAR NOT NULL,"register" BOOLEAN NOT NULL,"ttl" INT NOT NULL,"uri" LONGVARCHAR NOT NULL) +CREATE MEMORY TABLE "restcomm_media_servers" ( "ms_id" INT GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, "local_ip" VARCHAR(34) NOT NULL, "local_port" INT NOT NULL, "remote_ip" VARCHAR(34) NOT NULL UNIQUE, "remote_port" INT NOT NULL, "compatibility" VARCHAR(34) DEFAULT 'rms', "response_timeout" VARCHAR(34), "external_address" VARCHAR(34)) +CREATE MEMORY TABLE "restcomm_media_resource_broker_entity" ("conference_sid" VARCHAR(34) NOT NULL, "slave_ms_id" VARCHAR(34) NOT NULL, "slave_ms_bridge_ep_id" VARCHAR(34),"slave_ms_cnf_ep_id" VARCHAR(34),"is_bridged_together" BOOLEAN DEFAULT FALSE,PRIMARY KEY ("conference_sid" , "slave_ms_id")) +CREATE MEMORY TABLE PUBLIC."restcomm_extensions_configuration"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"extension" VARCHAR(255) NOT NULL,"configuration_data" VARCHAR(16777216),"configuration_type" VARCHAR(255) NOT NULL,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP, "enabled" BOOLEAN DEFAULT TRUE NOT NULL) +CREATE MEMORY TABLE "restcomm_geolocation"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "date_executed" DATETIME NOT NULL, "account_sid" VARCHAR(34) NOT NULL, "source" VARCHAR(30), "device_identifier" VARCHAR(30) NOT NULL, "geolocation_type" VARCHAR(15) NOT NULL, "response_status" VARCHAR(30), "cell_id" VARCHAR(10), "location_area_code" VARCHAR(10), "mobile_country_code" INTEGER, "mobile_network_code" VARCHAR(3), "network_entity_address" BIGINT, "age_of_location_info" INTEGER, "device_latitude" VARCHAR(15), "device_longitude" VARCHAR(15), "accuracy" BIGINT, "physical_address" VARCHAR(50), "internet_address" VARCHAR(50), "formatted_address" VARCHAR(200), "location_timestamp" DATETIME, "event_geofence_latitude" VARCHAR(15), "event_geofence_longitude" VARCHAR(15), "radius" BIGINT, "geolocation_positioning_type" VARCHAR(15), "last_geolocation_response" VARCHAR(10), "cause" VARCHAR(150), "api_version" VARCHAR(10) NOT NULL, "uri" LONGVARCHAR NOT NULL) CREATE USER SA PASSWORD "" GRANT DBA TO SA SET WRITE_DELAY 10 diff --git a/restcomm/restcomm.dao/src/test/resources/restcomm.xml b/restcomm/restcomm.dao/src/test/resources/restcomm.xml new file mode 100644 index 0000000000..8f96ed1e3f --- /dev/null +++ b/restcomm/restcomm.dao/src/test/resources/restcomm.xml @@ -0,0 +1,605 @@ + + + + + + 2012-04-24 + + + false + + + /restcomm/audio + + + beep.wav + alert.wav + + + ${restcomm:home}/cache + /restcomm/cache + + + false + + + file://${restcomm:home}/recordings + /restcomm/recordings + + + /restcomm/errors + + + + + + true + + + false + + + true + + + + false + + + 5060 + WebRTCGW__1@ + WebRTCGW/1.0 + + + + + + + + false + + true + + + + + + + + + + + + + + + + + + + + 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.dao/src/test/resources/sms-messages.xml b/restcomm/restcomm.dao/src/test/resources/sms-messages.xml deleted file mode 100644 index 1d0d1d6d87..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/sms-messages.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - INSERT INTO "restcomm_sms_messages" ("sid", "date_created", "date_updated", "date_sent", "account_sid", "sender", "recipient", "body", "status", "direction", "price", - "api_version", "uri") VALUES (#{sid}, #{date_created}, #{date_updated}, #{date_sent}, #{account_sid}, #{sender}, #{recipient}, #{body}, - #{status}, #{direction}, #{price}, #{api_version}, #{uri}); - - - - - - - - DELETE FROM "restcomm_sms_messages" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_sms_messages" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_sms_messages" SET "date_sent"=#{date_sent}, "status"=#{status}, "price"=#{price} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dao/src/test/resources/transcriptions.xml b/restcomm/restcomm.dao/src/test/resources/transcriptions.xml deleted file mode 100644 index 087a362eb5..0000000000 --- a/restcomm/restcomm.dao/src/test/resources/transcriptions.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - INSERT INTO "restcomm_transcriptions" ("sid", "date_created", "date_updated", "account_sid", "status", "recording_sid", "duration", "transcription_text", "price", "uri") - VALUES (#{sid}, #{date_created}, #{date_updated}, #{account_sid}, #{status}, #{recording_sid}, #{duration}, #{transcription_text}, #{price}, #{uri}); - - - - - - - - - - DELETE FROM "restcomm_transcriptions" WHERE "sid"=#{sid}; - - - - DELETE FROM "restcomm_transcriptions" WHERE "account_sid"=#{account_sid}; - - - - UPDATE "restcomm_transcriptions" SET "status"=#{status} WHERE "sid"=#{sid}; - - \ No newline at end of file diff --git a/restcomm/restcomm.dns.api/pom.xml b/restcomm/restcomm.dns.api/pom.xml new file mode 100644 index 0000000000..79061674ef --- /dev/null +++ b/restcomm/restcomm.dns.api/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT + + restcomm-connect.dns.api + + + + log4j + log4j + provided + + + org.restcomm + restcomm-connect.commons + ${project.version} + + + + org.apache.tomcat + tomcat-coyote + provided + + + + diff --git a/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManager.java b/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManager.java new file mode 100644 index 0000000000..d3dc250a02 --- /dev/null +++ b/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManager.java @@ -0,0 +1,79 @@ +/* + * 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.dns; + +import org.apache.commons.configuration.Configuration; + +public interface DnsProvisioningManager { + + /** + * Initialize the Manager with the RestComm configuration passed in restcomm.xml + * + * @param dnsConfiguration the configuration from restcomm.xml contained within tags + */ + void init(Configuration dnsConfiguration); + + /** + * @param name The name of the domain you want to perform the action on. + * Enter a sub domain name only. For example to add 'company1.restcomm.com', + * provide only 'company1' and provide hosted zone for 'restcomm.com' + * @param hostedZoneId hostedZoneId The ID of the hosted zone that contains the resource record sets that you want to change. + * If none provided, then default will be used as per configuration + * @return true if operation successful, false otherwise. + */ + boolean createResourceRecord(final String name, final String hostedZoneId); + + /** + * @param name The name of the domain you want to read. + * Enter a sub domain name only. For example to add 'company1.restcomm.com', + * provide only 'company1' and provide hosted zone for 'restcomm.com' + * @param hostedZoneId hostedZoneId The ID of the hosted zone that contains the resource record sets that you want to change. + * If none provided, then default will be used as per configuration + * @return true if resource record exists, false otherwise. + */ + boolean doesResourceRecordAlreadyExists(final String name, final String hostedZoneId); + + /** + * @param name The name of the domain you want to perform the action on. + * Enter a sub domain name only. For example to add 'company1.restcomm.com', + * provide only 'company1' and provide hosted zone for 'restcomm.com' + * @param hostedZoneId hostedZoneId The ID of the hosted zone that contains the resource record sets that you want to change. + * If none provided, then default will be used as per configuration + * @return true if operation successful, false otherwise. + */ + boolean updateResourceRecord(final String name, final String hostedZoneId); + + /** + * @param name The name of the domain you want to perform the action on. + * Enter a sub domain name only. For example to add 'company1.restcomm.com', + * provide only 'company1' and provide hosted zone for 'restcomm.com' + * @param hostedZoneId hostedZoneId The ID of the hosted zone that contains the resource record sets that you want to change. + * If none provided, then default will be used as per configuration + * @return true if operation successful, false otherwise. + */ + boolean deleteResourceRecord(final String name, final String hostedZoneId); + + /** + * @param subDomainName + * @param hostedZoneId + * @return + */ + String getCompleteDomainName(String subDomainName, final String hostedZoneId); +} diff --git a/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManagerProvider.java b/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManagerProvider.java new file mode 100644 index 0000000000..ff88c84876 --- /dev/null +++ b/restcomm/restcomm.dns.api/src/main/java/org/restcomm/connect/dns/DnsProvisioningManagerProvider.java @@ -0,0 +1,93 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2014, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it and/or modify + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +package org.restcomm.connect.dns; + +import javax.servlet.ServletContext; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.loader.ObjectFactory; +import org.restcomm.connect.commons.loader.ObjectInstantiationException; + +/** + * A single place to create the dns provisioning manager + * + * @author maria farooq + */ +public class DnsProvisioningManagerProvider { + protected Logger logger = Logger.getLogger(DnsProvisioningManagerProvider.class); + + protected Configuration configuration; + protected ServletContext context; + + public DnsProvisioningManagerProvider(Configuration configuration, ServletContext context) { + this.configuration = configuration; + this.context = context; + } + + /** + * @return initialized instance of DnsProvisioningManager + */ + private DnsProvisioningManager create() { + Configuration dnsProvisioningConfiguration = configuration.subset("dns-provisioning"); + if (dnsProvisioningConfiguration == null || dnsProvisioningConfiguration.isEmpty()){ + logger.warn("dns-provisioning configuration is null or empty"); + return null; + } + final boolean enabled = configuration.getBoolean("dns-provisioning[@enabled]", false); + if(!enabled){ + logger.warn("dns-provisioning is disabled in configuration"); + return null; + } + final String dnsProvisioningManagerClass = configuration.getString("dns-provisioning[@class]"); + if(dnsProvisioningManagerClass == null || dnsProvisioningManagerClass.trim().equals("")){ + logger.warn("dns-provisioning is enabled but manager class is null or empty"); + return null; + } + DnsProvisioningManager dnsProvisioningManager; + try { + dnsProvisioningManager = (DnsProvisioningManager) new ObjectFactory(getClass().getClassLoader()) + .getObjectInstance(dnsProvisioningManagerClass); + dnsProvisioningManager.init(dnsProvisioningConfiguration); + } catch (ObjectInstantiationException e) { + throw new RuntimeException(e); + } + return dnsProvisioningManager; + } + + /** + * Tries to retrieve the manager from the Servlet context. If it's not there it creates is, stores it + * in the context and also returns it. + * + * @param context + * @return + */ + public DnsProvisioningManager get() { + DnsProvisioningManager manager = (DnsProvisioningManager) context.getAttribute("DnsProvisioningManager"); + if (manager != null) // ok, it's already in the context. Return it + return manager; + manager = create(); + // put it into the context for next time that is requested + context.setAttribute("DnsProvisioningManager", manager); + return manager; + } + +} diff --git a/restcomm/restcomm.docs/.project b/restcomm/restcomm.docs/.project new file mode 100644 index 0000000000..2b1d8219be --- /dev/null +++ b/restcomm/restcomm.docs/.project @@ -0,0 +1,17 @@ + + + restcomm-docs + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + + diff --git a/restcomm/restcomm.docs/.settings/org.eclipse.m2e.core.prefs b/restcomm/restcomm.docs/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000000..f897a7f1cb --- /dev/null +++ b/restcomm/restcomm.docs/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/restcomm/restcomm.docs/jdocbook-mobicents/pom.xml b/restcomm/restcomm.docs/jdocbook-mobicents/pom.xml deleted file mode 100644 index 6a8e497867..0000000000 --- a/restcomm/restcomm.docs/jdocbook-mobicents/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - com.telestax.servlet - restcomm-docs - 7.2.0-SNAPSHOT - - - restcomm-docs-jdocbook-mobicents - - 4.0.0 - - jdocbook - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - generate-resources - - unpack - - - - - ${pom.groupId} - restcomm-docs-sources-mobicents - ${pom.version} - jar - true - ${project.build.directory}/docbook/resources - - - - - - - - org.jboss.maven.plugins - maven-jdocbook-plugin - 2.3.5 - true - - - org.mobicents.jdocbook - telestax-xslt-ns - 1.3.0.FINAL - - - org.mobicents.jdocbook - telestax-community-style - jdocbook-style - 1.3.0.FINAL - - - - RestComm_User_Guide.xml - ${project.build.directory}/docbook/resources - - ${project.build.directory}/docbook/resources/en-US - - images/* - - - - - pdf - classpath:/xslt/org/jboss/pdf.xsl - RestComm_User_Guide.pdf - - - html - classpath:/xslt/org/jboss/xhtml.xsl - index.html - - - html_single - classpath:/xslt/org/jboss/xhtml-single.xsl - index.html - - - - true - - - 1.72.0 - - - - - - - diff --git a/restcomm/restcomm.docs/jdocbook-telscale/pom.xml b/restcomm/restcomm.docs/jdocbook-telscale/pom.xml deleted file mode 100644 index 5e2faebee9..0000000000 --- a/restcomm/restcomm.docs/jdocbook-telscale/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - com.telestax.servlet - restcomm-docs - 7.2.0-SNAPSHOT - - - restcomm-docs-jdocbook-telscale - - 4.0.0 - - jdocbook - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - generate-resources - - unpack - - - - - ${pom.groupId} - restcomm-docs-sources-telscale - ${pom.version} - jar - true - ${project.build.directory}/docbook/resources - - - - - - - - org.jboss.maven.plugins - maven-jdocbook-plugin - 2.3.5 - true - - - org.mobicents.jdocbook - telestax-xslt-ns - 1.3.0.FINAL - - - org.mobicents.jdocbook - telestax-telscale-style - jdocbook-style - 1.3.0.FINAL - - - - RestComm_User_Guide.xml - ${project.build.directory}/docbook/resources - - ${project.build.directory}/docbook/resources/en-US - - images/* - - - - - pdf - classpath:/xslt/org/jboss/pdf.xsl - RestComm_User_Guide.pdf - - - html - classpath:/xslt/org/jboss/xhtml.xsl - index.html - - - html_single - classpath:/xslt/org/jboss/xhtml-single.xsl - index.html - - - - true - - - 1.72.0 - - - - - - - diff --git a/restcomm/restcomm.docs/pom.xml b/restcomm/restcomm.docs/pom.xml index f8f1753fca..55f98ac5db 100644 --- a/restcomm/restcomm.docs/pom.xml +++ b/restcomm/restcomm.docs/pom.xml @@ -3,57 +3,20 @@ 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - com.telestax.servlet - restcomm-docs + org.restcomm + restcomm-connect-docs pom - sources + sources-asciidoc - - - release - - sources-mobicents - sources-telscale - jdocbook-mobicents - jdocbook-telscale - - - - all - - true - - - sources-mobicents - sources-telscale - jdocbook-mobicents - jdocbook-telscale - - - - mobicents - - sources-mobicents - jdocbook-mobicents - - - - telscale - - sources-telscale - jdocbook-telscale - - - diff --git a/restcomm/restcomm.docs/sources-asciidoc/pom.xml b/restcomm/restcomm.docs/sources-asciidoc/pom.xml new file mode 100644 index 0000000000..5f775d6d01 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/pom.xml @@ -0,0 +1,168 @@ + + + + 4.0.0 + + + org.restcomm + restcomm-connect-docs + 8.3.0-SNAPSHOT + + + restcomm-connect-docs-sources + restcomm-connect Connect :: Docs :: ${pom.artifactId} + + + 1.5.3 + 1.5.0-alpha.11 + 1.5.4 + 1.5.4 + 1.7.21 + + + + + + ${basedir}/src/main/asciidoc + true + + + + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor.maven.plugin.version} + + + org.asciidoctor + asciidoctorj-pdf + ${asciidoctorj.pdf.version} + + + + org.jruby + jruby-complete + ${jruby.version} + + + + org.asciidoctor + asciidoctorj + ${asciidoctorj.version} + + + org.asciidoctor + asciidoctorj-diagram + ${asciidoctorj.diagram.version} + + + + + + asciidoctor-diagram + + + + + output-html-website + generate-resources + + process-asciidoc + + + html5 + ${project.build.directory}/generated-docs/html-website + + + ./images/.. + + font + true + + - + true + true + ${basedir}/src/main/asciidoc/stylesheets/telestax.css + ${project.version} + Connect + Restcomm + JBoss Application Server + https://github.com/Restcomm/Restcomm-Connect/issues + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + + true + + + + output-html-book + generate-resources + + process-asciidoc + + + html5 + ${project.build.directory}/generated-docs/html-book + + + ./images/.. + + font + true + + - + false + true + + ${project.version} + Restcomm-Connect + Restcomm + JBoss Application Server + https://github.com/Restcomm/Restcomm-Connect/issues + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + + true + + + + generate-pdf-doc + generate-resources + + process-asciidoc + + + pdf + ${project.build.directory}/generated-docs/pdf + + rouge + + ./images/.. + font + + + + - + ${project.version} + Restcomm-Connect + Restcomm + JBoss Application Server + https://github.com/Restcomm/Restcomm-Connect/issues + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + https://github.com/Restcomm/Restcomm-Connect + + + + + + + + diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Conventions.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Conventions.adoc new file mode 100644 index 0000000000..b302e6e53f --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Conventions.adoc @@ -0,0 +1,158 @@ + += Document Conventions + +This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information. + +In PDF and paper editions, this manual uses typefaces drawn from the https://fedorahosted.org/liberation-fonts/[Liberation Fonts] set. +The Liberation Fonts set is also used in HTML editions if the set is installed on your system. +If not, alternative but equivalent typefaces are displayed. +Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default. + +== Typographic Conventions + +Four typographic conventions are used to call attention to specific words and phrases. +These conventions, and the circumstances they apply to, are as follows. + +`Mono-spaced Bold` + +Used to highlight system input, including shell commands, file names and paths. +Also used to highlight key caps and key-combinations. +For example: + +[quote] +To see the contents of the file [path]_my_next_bestselling_novel_ in your current working directory, enter the `cat my_next_bestselling_novel` command at the shell prompt and press kbd:[Enter] to execute the command. + +The above includes a file name, a shell command and a key cap, all presented in Mono-spaced Bold and all distinguishable thanks to context. + +Key-combinations can be distinguished from key caps by the hyphen connecting each part of a key-combination. +For example: + +____ +Press kbd:[Enter] to execute the command. + +Press to switch to the first virtual terminal. +Press to return to your X-Windows session. +____ + +The first sentence highlights the particular key cap to press. +The second highlights two sets of three key caps, each set pressed simultaneously. + +If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in `Mono-spaced Bold`. +For example: + +[quote] +File-related classes include [class]`filesystem` for file systems, [class]`file` for files, and [class]`dir` for directories. +Each class has its own associated set of permissions. + +[app]`Proportional Bold` + +This denotes words or phrases encountered on a system, including application names; dialogue box text; labelled buttons; check-box and radio button labels; menu titles and sub-menu titles. +For example: + +____ +Choose menu:System > Preferences > Mouse[] from the main menu bar to launch [app]`Mouse Preferences`. +In the [label]#Buttons# tab, click the [label]#Left-handed mouse# check box and click btn:[Close] to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand). + +To insert a special character into a [app]`gedit` file, choose menu:Applications > Accessories > Character Map[] from the main menu bar. +Next, choose menu:Search > Find[] from the [app]`Character Map` menu bar, type the name of the character in the [label]#Search# field and click btn:[Next]. +The character you sought will be highlighted in the [label]#Character Table#. +Double-click this highlighted character to place it in the [label]#Text to copy# field and then click the btn:[Copy] button. +Now switch back to your document and choose menu:Edit > Paste[] from the [app]`gedit` menu bar. +____ + +The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in Proportional Bold and all distinguishable by context. + +Note the menu:>[] shorthand used to indicate traversal through a menu and its sub-menus. +This is to avoid the difficult-to-follow 'Select from the menu:Preferences[] sub-menu in the menu:System[] menu of the main menu bar' approach. + +`Mono-spaced Bold Italic` or [app]`Proportional Bold Italic` + +Whether Mono-spaced Bold or Proportional Bold, the addition of Italics indicates replaceable or variable text. +Italics denotes text you do not input literally or displayed text that changes depending on circumstance. +For example: + +____ +To connect to a remote machine using ssh, type `ssh username@domain.name` at a shell prompt. +If the remote machine is [path]_example.com_ and your username on that machine is john, type `ssh john@example.com`. + +The `mount -o remount file-system` command remounts the named file system. +For example, to remount the [path]_/home_ file system, the command is `mount -o remount /home`. + +To see the version of a currently installed package, use the `rpm -q package` command. +It will return a result as follows: `package-version-release`. +____ + +Note the words in bold italics above —username, domain.name, file-system, package, version and release. +Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system. + +Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. +For example: + +[quote] +When the Apache HTTP Server accepts requests, it dispatches child processes or threads to handle them. +This group of child processes or threads is known as a [term]_server-pool_. +Under Apache HTTP Server 2.0, the responsibility for creating and maintaining these server-pools has been abstracted to a group of modules called [term]_Multi-Processing Modules_ ([term]_MPMs_). Unlike other modules, only one module from the MPM group can be loaded by the Apache HTTP Server. + +== Pull-quote Conventions + +Two, commonly multi-line, data types are set off visually from the surrounding text. + +Output sent to a terminal is set in `Mono-spaced Roman` and presented thus: + +---- + +books Desktop documentation drafts mss photos stuff svn +books_tests Desktop1 downloads images notes scripts svgs +---- + +Source-code listings are also set in `Mono-spaced Roman` but are presented and highlighted as follows: + +[source,java] +---- + +package org.jboss.book.jca.ex1; + +import javax.naming.InitialContext; + +public class ExClient +{ + public static void main(String args[]) + throws Exception + { + InitialContext iniCtx = new InitialContext(); + Object ref = iniCtx.lookup("EchoBean"); + EchoHome home = (EchoHome) ref; + Echo echo = home.create(); + + System.out.println("Created Echo"); + + System.out.println("Echo.echo('Hello') = " + echo.echo("Hello")); + } + +} +---- + +== Notes and Warnings + +Finally, we use three visual styles to draw attention to information that might otherwise be overlooked. + +.Note +[NOTE] +==== +A note is a tip or shortcut or alternative approach to the task at hand. +Ignoring a note should have no negative consequences, but you might miss out on a trick that makes your life easier. +==== + +.Important +[IMPORTANT] +==== +Important boxes detail things that are easily missed: configuration changes that only apply to the current session, or services that need restarting before an update will apply. +Ignoring Important boxes won't cause data loss but may cause irritation and frustration. +==== + +.Warning +[WARNING] +==== +A Warning should not be ignored. +Ignoring warnings will most likely cause data loss. +==== diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Java_Development_Kit-Installing_Configuring_and_Running.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Java_Development_Kit-Installing_Configuring_and_Running.adoc new file mode 100644 index 0000000000..a82cd8565e --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Java_Development_Kit-Installing_Configuring_and_Running.adoc @@ -0,0 +1,94 @@ + +:sectnums!: + +[appendix] +[[_jdk_installing_configuring_and_running]] += Java Development Kit (): Installing, Configuring and Running + +The [app]` Platform` is written in Java; therefore, before running any [app]`` server, you must have a working Java Runtime Environment () or Java Development Kit () installed on your system. +In addition, the JRE or JDK you are using to run [app]`` must be version 5 or higherfootnote:[At this point in time, it is possible to run most servers, such as the JAIN SLEE, using a Java 6 JRE or JDK. Be aware, however, that presently the XML Document Management Server does not run on Java 6. We suggest checking the web site, forums or discussion pages if you need to inquire about the status of running the XML Document Management Server with Java 6.]. + +.Should I Install the JRE or JDK? +Although you can run [app]`` servers using the Java Runtime Environment, we assume that most users are developers interested in developing Java-based, [app]``-driven solutions. +Therefore, in this guide we take the tact of showing how to install the full Java Development Kit. + +.Should I Install the 32-Bit or the 64-Bit JDK, and Does It Matter? +Briefly stated: if you are running on a 64-Bit Linux or Windows platform, you should consider installing and running the 64-bit JDK over the 32-bit one. +Here are some heuristics for determining whether you would rather run the 64-bit Java Virtual Machine (JVM) over its 32-bit cousin for your application: + +* Wider datapath: the pipe between RAM and CPU is doubled, which improves the performance of memory-bound applications when using a 64-bit JVM. +* 64-bit memory addressing gives virtually unlimited (1 exabyte) heap allocation. + However large heaps affect garbage collection. +* Applications that run with more than 1.5 GB of RAM (including free space for garbage collection optimization) should utilize the 64-bit JVM. +* Applications that run on a 32-bit JVM and do not require more than minimal heap sizes will gain nothing from a 64-bit JVM. + Barring memory issues, 64-bit hardware with the same relative clock speed and architecture is not likely to run Java applications faster than their 32-bit cousin. + +Note that the following instructions detail how to download and install the 32-bit JDK, although the steps are nearly identical for installing the 64-bit version. + +.Downloading +You can download the Sun JDK 5.0 (Java 2 Development Kit) from Sun's website: http://java.sun.com/javase/downloads/index_jdk5.jsp. +Click on the [label]#Download# link next to "JDK 5.0 Update [replaceable]``" (where [replaceable]`` is the latest minor version release number). On the next page, select your language and platform (both architecture--whether 32- or 64-bit--and operating system), read and agree to the `Java Development Kit 5.0 License Agreement`, and proceed to the download page. + +The Sun website will present two download alternatives to you: one is an RPM inside a self-extracting file (for example, [path]_jdk-1_5_0_16-linux-i586-rpm.bin_), and the other is merely a self-extracting file (e.g. [path]_jdk-1_5_0_16-linux-i586.bin_). If you are installing the JDK on Red Hat Enterprise Linux, Fedora, or another RPM-based Linux system, we suggest that you download the self-extracting file containing the RPM package, which will set up and use the SysV service scripts in addition to installing the JDK. +We also suggest installing the self-extracting RPM file if you will be running [app]`` in a production environment. + +.Installing +The following procedures detail how to install the Java Development Kit on both Linux and Windows. + +.Procedure: Installing the JDK on Linux +. Regardless of which file you downloaded, you can install it on Linux by simply making sure the file is executable and then running it: ++ +---- +~]$ chmod +x "jdk-1_5_0_-linux--rpm.bin" +~]$ ./"jdk-1_5_0_-linux--rpm.bin" +---- + + +.You Installed Using the Non-RPM Installer, but Want the SysV Service Scripts +[NOTE] +==== +If you download the non-RPM self-extracting file (and installed it), and you are running on an RPM-based system, you can still set up the SysV service scripts by downloading and installing one of the `-compat` packages from the JPackage project. +Remember to download the `-compat` package which corresponds correctly to the minor release number of the JDK you installed. +The compat packages are available from link:ftp://jpackage.hmdc.harvard.edu/JPackage/1.7/generic/RPMS.non-free/. +==== + +IMPORTANT: You do not need to install a `-compat` package in addition to the JDK if you installed the self-extracting RPM file! The `-compat` package merely performs the same SysV service script set up that the RPM version of the JDK installer does. + +.Procedure: Installing the JDK on Windows +. Using Explorer, simply double-click the downloaded self-extracting installer and follow the instructions to install the JDK. + +.Configuring +Configuring your system for the JDK consists in two tasks: setting the [var]`JAVA_HOME` environment variable, and ensuring that the system is using the proper JDK (or JRE) using the `alternatives` command. +Setting [var]`JAVA_HOME` usually overrides the values for `java`, `javac` and `java_sdk_1.5.0` in `alternatives`, but we will set them all just to be safe and consistent. + +Setting the [var]`JAVA_HOME` Environment Variable on Generic Linux:: + After installing the JDK, you must ensure that the [var]`JAVA_HOME` environment variable exists and points to the location of your JDK installation. + +Setting [var]`java`, [var]`javac` and [var]`java_sdk_1.5.0` Using the `alternatives` command :: + _As the root user_, call `/usr/sbin/alternatives` with the [option]`--config java` option to select between JDKs and JREs installed on your system: + +Setting the [var]`JAVA_HOME` Environment Variable on Windows:: + For information on how to set environment variables in Windows, refer to http://support.microsoft.com/kb/931715. + +.Testing +Finally, to make sure that you are using the correct JDK or Java version (5 or higher), and that the java executable is in your [var]`PATH`, run the `java -version + ` command in the terminal from your home directory: + +---- +~]$ java -version +java version "1.5.0_16" +Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b03) +Java HotSpot(TM) Client VM (build 1.5.0_16-b03, mixed mode, sharing) +---- + +.Uninstalling +There is usually no reason (other than space concerns) to remove a particular JDK from your system, given that you can switch between JDKs and JREs easily using `alternatives`, and/or by setting [var]`JAVA_HOME`. + +.Uninstalling the JDK on Linux +On RPM-based systems, you can uninstall the JDK using the `yum remove + ` command. + +.Uninstalling the JDK on Windows +On Windows systems, check the JDK entry in the `Start` menu for an uninstall command, or use `Add/Remove Programs`. + +:sectnums: \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Preface.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Preface.adoc new file mode 100644 index 0000000000..5f5e68a5fe --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Preface.adoc @@ -0,0 +1,15 @@ + +:sectnums!: + +[preface] += Preface + +:leveloffset: 1 +include::Section-Conventions.adoc[] +:leveloffset: 0 + +:leveloffset: 1 +include::Section-Feedback.adoc[] +:leveloffset: 0 + +:sectnums: \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Conventions.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Conventions.adoc new file mode 100644 index 0000000000..32d4ef81a9 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Conventions.adoc @@ -0,0 +1,158 @@ + += Document Conventions + +This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information. + +In PDF and paper editions, this manual uses typefaces drawn from the https://fedorahosted.org/liberation-fonts/[Liberation Fonts] set. +The Liberation Fonts set is also used in HTML editions if the set is installed on your system. +If not, alternative but equivalent typefaces are displayed. +Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default. + +== Typographic Conventions + +Four typographic conventions are used to call attention to specific words and phrases. +These conventions, and the circumstances they apply to, are as follows. + +`Mono-spaced Bold` + +Used to highlight system input, including shell commands, file names and paths. +Also used to highlight key caps and key-combinations. +For example: + +[quote] +To see the contents of the file [path]_my_next_bestselling_novel_ in your current working directory, enter the `cat my_next_bestselling_novel` command at the shell prompt and press kbd:[Enter] to execute the command. + +The above includes a file name, a shell command and a key cap, all presented in Mono-spaced Bold and all distinguishable thanks to context. + +Key-combinations can be distinguished from key caps by the hyphen connecting each part of a key-combination. +For example: + +____ +Press kbd:[Enter] to execute the command. + +Press to switch to the first virtual terminal. +Press to return to your X-Windows session. +____ + +The first sentence highlights the particular key cap to press. +The second highlights two sets of three key caps, each set pressed simultaneously. + +If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in `Mono-spaced Bold`. +For example: + +[quote] +File-related classes include [class]`filesystem` for file systems, [class]`file` for files, and [class]`dir` for directories. +Each class has its own associated set of permissions. + +[app]`Proportional Bold` + +This denotes words or phrases encountered on a system, including application names; dialogue box text; labelled buttons; check-box and radio button labels; menu titles and sub-menu titles. +For example: + +____ +Choose menu:System > Preferences > Mouse[] from the main menu bar to launch [app]`Mouse Preferences`. +In the [label]#Buttons# tab, click the [label]#Left-handed mouse# check box and click btn:[Close] to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand). + +To insert a special character into a [app]`gedit` file, choose menu:Applications > Accessories > Character Map[] from the main menu bar. +Next, choose menu:Search > Find[] from the [app]`Character Map` menu bar, type the name of the character in the [label]#Search# field and click btn:[Next]. +The character you sought will be highlighted in the [label]#Character Table#. +Double-click this highlighted character to place it in the [label]#Text to copy# field and then click the btn:[Copy] button. +Now switch back to your document and choose menu:Edit > Paste[] from the [app]`gedit` menu bar. +____ + +The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in Proportional Bold and all distinguishable by context. + +Note the menu:>[] shorthand used to indicate traversal through a menu and its sub-menus. +This is to avoid the difficult-to-follow 'Select from the menu:Preferences[] sub-menu in the menu:System[] menu of the main menu bar' approach. + +`Mono-spaced Bold Italic` or [app]`Proportional Bold Italic` + +Whether Mono-spaced Bold or Proportional Bold, the addition of Italics indicates replaceable or variable text. +Italics denotes text you do not input literally or displayed text that changes depending on circumstance. +For example: + +____ +To connect to a remote machine using ssh, type `ssh username@domain.name` at a shell prompt. +If the remote machine is [path]_example.com_ and your username on that machine is john, type `ssh john@example.com`. + +The `mount -o remount file-system` command remounts the named file system. +For example, to remount the [path]_/home_ file system, the command is `mount -o remount /home`. + +To see the version of a currently installed package, use the `rpm -q package` command. +It will return a result as follows: `package-version-release`. +____ + +Note the words in bold italics above —username, domain.name, file-system, package, version and release. +Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system. + +Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. +For example: + +[quote] +When the Apache HTTP Server accepts requests, it dispatches child processes or threads to handle them. +This group of child processes or threads is known as a [term]_server-pool_. +Under Apache HTTP Server 2.0, the responsibility for creating and maintaining these server-pools has been abstracted to a group of modules called [term]_Multi-Processing Modules_ ([term]_MPMs_). Unlike other modules, only one module from the MPM group can be loaded by the Apache HTTP Server. + +== Pull-quote Conventions + +Two, commonly multi-line, data types are set off visually from the surrounding text. + +Output sent to a terminal is set in `Mono-spaced Roman` and presented thus: + +---- + +books Desktop documentation drafts mss photos stuff svn +books_tests Desktop1 downloads images notes scripts svgs +---- + +Source-code listings are also set in `Mono-spaced Roman` but are presented and highlighted as follows: + +[source,java] +---- + +package org.jboss.book.jca.ex1; + +import javax.naming.InitialContext; + +public class ExClient +{ + public static void main(String args[]) + throws Exception + { + InitialContext iniCtx = new InitialContext(); + Object ref = iniCtx.lookup("EchoBean"); + EchoHome home = (EchoHome) ref; + Echo echo = home.create(); + + System.out.println("Created Echo"); + + System.out.println("Echo.echo('Hello') = " + echo.echo("Hello")); + } + +} +---- + +== Notes and Warnings + +Finally, we use three visual styles to draw attention to information that might otherwise be overlooked. + +.Note +[NOTE] +==== +A note is a tip or shortcut or alternative approach to the task at hand. +Ignoring a note should have no negative consequences, but you might miss out on a trick that makes your life easier. +==== + +.Important +[IMPORTANT] +==== +Important boxes detail things that are easily missed: configuration changes that only apply to the current session, or services that need restarting before an update will apply. +Ignoring Important boxes won't cause data loss but may cause irritation and frustration. +==== + +.Warning +[WARNING] +==== +A Warning should not be ignored. +Ignoring warnings will most likely cause data loss. +==== \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Feedback.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Feedback.adoc new file mode 100644 index 0000000000..54e03b2742 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Section-Feedback.adoc @@ -0,0 +1,16 @@ + += Provide feedback to the authors! +(((feedback))) + +If you find a typographical error in this manual, or if you have thought of a way to make this manual better, we would love to hear from you! Please submit a report in the the {this-issue.tracker.ur}, against the product {this-platform} {this-application}` `, or contact the authors. + +When submitting a bug report, be sure to mention the manual's identifier: {this-platform} {this-application} + +If you have a suggestion for improving the documentation, try to be as specific as possible when describing it. +If you have found an error, please include the section number and some of the surrounding text so we can find it easily. + +ifdef::backend-docbook[] +[index] +== Index +// Generated automatically by the DocBook toolchain. +endif::backend-docbook[] diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Setting_the_JBOSS_HOME_Environment_Variable.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Setting_the_JBOSS_HOME_Environment_Variable.adoc new file mode 100644 index 0000000000..8dfaa152c0 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/Common_Content/Setting_the_JBOSS_HOME_Environment_Variable.adoc @@ -0,0 +1,85 @@ + +:sectnums!: + +[appendix] +[[_jboss_home_setup]] += Setting the JBOSS_HOME Environment Variable + +The [app]` Platform` ([app]``) is built on top of the [app]``. +You do not need to set the [var]`JBOSS_HOME` environment variable to run any of the [app]` Platform` servers _unless_ [var]`JBOSS_HOME` is _already_ set. + +The best way to know for sure whether [var]`JBOSS_HOME` was set previously or not is to perform a simple check which may save you time and frustration. + +.Checking to See If JBOSS_HOME is Set on Unix +At the command line, `echo` `$JBOSS_HOME` to see if it is currently defined in your environment: + +---- +~]$ echo $JBOSS_HOME +---- + +The [app]` Platform` and most &THIS.PLATFORM; servers are built on top of the [app]`` ([app]``). When the [app]` Platform` or &THIS.PLATFORM; servers are built _from source_, then [var]`JBOSS_HOME` _must_ be set, because the &THIS.PLATFORM; files are installed into (or "`over top of`" if you prefer) a clean [app]`` installation, and the build process assumes that the location pointed to by the [var]`JBOSS_HOME` environment variable at the time of building is the [app]`` installation into which you want it to install the &THIS.PLATFORM; files. + +This guide does not detail building the [app]` Platform` or any &THIS.PLATFORM; servers from source. +It is nevertheless useful to understand the role played by [app]`JBoss AS` and [var]`JBOSS_HOME` in the &THIS.PLATFORM; ecosystem. + +The immediately-following section considers whether you need to set [var]`JBOSS_HOME` at all and, if so, when. +The subsequent sections detail how to set [var]`JBOSS_HOME` on Unix and Windows + +IMPORTANT: Even if you fall into the category below of _not needing_ to set [var]`JBOSS_HOME`, you may want to for various reasons anyway. +Also, even if you are instructed that you do _not need_ to set [var]`JBOSS_HOME`, it is good practice nonetheless to check and make sure that [var]`JBOSS_HOME` actually _isn't_ set or defined on your system for some reason. +This can save you both time and frustration. + +You _DO NOT NEED_ to set [var]`JBOSS_HOME` if... + +* ...you have installed the [app]` Platform` binary distribution. +* ...you have installed a &THIS.PLATFORM;server binary distribution _which bundles [app]``._ + +You _MUST_ set [var]`JBOSS_HOME` if... + +* ...you are installing the [app]` Platform` or any of the &THIS.PLATFORM; servers _from source_. +* ...you are installing the [app]` Platform` binary distribution, or one of the &THIS.PLATFORM; server binary distributions, which _do not_ bundle [app]``. + +Naturally, if you installed the [app]` Platform` or one of the &THIS.PLATFORM; server binary releases which _do not_ bundle [app]``, yet requires it to run, then you should install before setting [var]`JBOSS_HOME` or proceeding with anything else. + +.Setting the JBOSS_HOME Environment Variable on Unix +The [var]`JBOSS_HOME` environment variable must point to the directory which contains all of the files for the [app]` Platform` or individual &THIS.PLATFORM; server that you installed. +As another hint, this topmost directory contains a [path]_bin_ subdirectory. + +Setting [var]`JBOSS_HOME` in your personal [path]_~/.bashrc_ startup script carries the advantage of retaining effect over reboots. +Each time you log in, the environment variable is sure to be set for you, as a user. +On Unix, it is possible to set [var]`JBOSS_HOME` as a system-wide environment variable, by defining it in [path]_/etc/bashrc_, but this method is neither recommended nor detailed in these instructions. + +.Procedure: To Set JBOSS_HOME on Unix... +. Open the [path]_~/.bashrc_ startup script, which is a hidden file in your home directory, in a text editor, and insert the following line on its own line while substituting for the actual install location on your system: ++ +---- +export JBOSS_HOME="/home////" +---- + +. Save and close the [path]_.bashrc_ startup script. +. You should `source` the [path]_.bashrc_ script to force your change to take effect, so that [var]`JBOSS_HOME` becomes set for the current sessionfootnote:[Note that any other terminals which were opened prior to your having altered .bashrc will need to source + ~/.bashrc as well should they require access to JBOSS_HOME.]. ++ +---- +~]$ source ~/.bashrc +---- + +. Finally, ensure that [var]`JBOSS_HOME` is set in the current session, and actually points to the correct location: ++ +NOTE: The command line usage below is based upon a binary installation of the [app]` Platform`. +In this sample output, [var]`JBOSS_HOME` has been set correctly to the [replaceable]`topmost_directory` of the [app]`` installation. +Note that if you are installing one of the standalone [app]`` servers (with [app]`JBoss AS` bundled!), then [var]`JBOSS_HOME` would point to the [replaceable]`topmost_directory` of your server installation. ++ +---- +~]$ echo $JBOSS_HOME +/home/silas/// +---- + + +.Setting the JBOSS_HOME Environment Variable on Windows +The [var]`JBOSS_HOME` environment variable must point to the directory which contains all of the files for the &THIS.PLATFORM;Platform or individual &THIS.PLATFORM;server that you installed. +As another hint, this topmost directory contains a [path]_bin_ subdirectory. + +For information on how to set environment variables in recent versions of Windows, refer to http://support.microsoft.com/kb/931715. + +:sectnums: \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/Restcomm - Overview Admin User Interface.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/Restcomm - Overview Admin User Interface.adoc new file mode 100644 index 0000000000..caf87ba334 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/Restcomm - Overview Admin User Interface.adoc @@ -0,0 +1,176 @@ +The admin user interface is a great way to perform repetitive Restcomm task in a orderly manner. Care has been taken to make the user experience intuitive for those new to the platform. In this chapter, you will learn how to use some of the features available to create Clients, Phone Numbers, Check Call Logs, Get Speech-to-Text Transcription and many more + += Login Interface + +You need to make sure Restcomm is running before you can use the Admin User Interface. When you are running on a local install, open your web browser and go to this url http://127.0.0.1:8080/ . You will see a screenshot similar to the one below + +image:./images/restcomm-admin-ui-1.png[restcomm-admin-ui-1,width=300,height=228] + +*Login Interface* + +[cols=",",options="header",] +|=================================================================================================== +|Number |Description +|1 |Host on which Restcomm is running +|2 |You can log in using either the default email address or the default administrator's account SID +|3 |The default password attached to the administrator's account +|=================================================================================================== + += Passwords, Sub Accounts Settings + +You should always change the passwords of the default Administrator's Account when you are in a production environment. When you click on the Administrators Account at the top right corner of the window, as shown in the screenshot below, you will be able to change passwords and create Sub Accounts. + +image:./images/restcomm-admin-ui-12.png[restcomm-admin-ui-12,width=300,height=196] + +*Account Settings* + +[cols=",",options="header",] +|========================================================== +|Number |Description +|1 |Shows the current Acount profile +|2 |You can create new Sub Accounts +|3 |Descriptive name of the user account +|4 |New password of the current logged in account +|5 |You can activate or suspend an account +|6 |There are three options, Trial, Basic and Full(default) +|7 |List of Sub Accounts +|========================================================== + += Dashboard + +This is the default page where you can get an overview of your Restcomm Installation. + +image:./images/restcomm-admin-ui-2.png[restcomm-admin-ui-2,width=300,height=250] + +*Dashboard* + +[cols=",",options="header",] +|================================================================================================================================================ +|Number |Description +|1 |Account SID is the default used by the Administrator's account +|2 |The Auth Token is the password that is required for any Restcomm operation. You can click on the hidden button to reveal the hashed password. +|3 |The Debugger lets you troubleshoot any issues you might encounter using Restcomm +|4 |A quick way to get all the API exposed by Restcomm +|5 |Additional information about Calls parsed by Restcomm +|6 |Additional information about SMS parsed by Restcomm +|================================================================================================================================================ + += Restcomm Numbers + +This will show the default demo applications that come with Restcomm. When you start creating applications and attaching numbers, they will also be displayed on this page. + +image:./images/restcomm-admin-ui-3.png[restcomm-admin-ui-3,width=300,height=183] + +*Restcomm Numbers* + +[cols=",",options="header",] +|====================================================================================================================================================================================================== +|Number |Description +|1 |The number 1235 is attached to the hello-world.xml application. You must have configured VoiceRSS text-to-speech to use this application +|2 |The number 1236 is attached to a the Gather verb. It will ask you to enter a number and you can hear the number you enter. You must have configured VoiceRSS text-to-speech to use this application +|3 |The number 1234 plays a pre-recorded file. +|4 |This icon lets you edit the Name of the entry to a more descriptive one. +|5 |This button lets you create a new number that can be attached to a RCML +|====================================================================================================================================================================================================== + +[[register-number]] += Register Number + +When you click on the Register Number button, you will see a screenshot similar to the one below. This will allow you to create a new phone number that can be attached to a Restcomm application. + +image:./images/restcomm-admin-ui-4.png[restcomm-admin-ui-4,width=245,height=300] + +*Table Restcomm Numbers* + +[cols=",",options="header",] +|================================================================================================================ +|Number |Description +|1 |The field to enter the phone number. +|2 |This button will show advanced options if you want to add more features to the phone number like the VoiceUrl +|3 |The friendly name is any descriptive text for your phone number +|4 |See the Rest API link:[Chapter] for more information +|5 |See the Rest API link:[Chapter]for more information +|================================================================================================================ + +[[edit-update-number]] += Edit Update Number + +Editing a phone number can be done by clicking on the number, the screenshot below shows how you can edit the number 1235. You can change the VoiceUrl to which the number is attached. + +image:./images/restcomm-admin-ui-5.png[restcomm-admin-ui-5,width=244,height=300] + +*Edit Update Numbers* + +[cols=",",options="header",] +|============================================================================================== +|Number |Description +|1 |You can link the phone number to a VoiceUrl application. See the REST API for more details. +|2 |You can link the phone number to a SMS application. See the REST API for more details +|3 |You can link the phone number to a USSD application. See the REST API for more details +|4 |Caller Id lookup requires a CNAM provier +|5 |You can save your changes or press close to discard the changes +|============================================================================================== + += SIP Clients + +SIP Client is a feature that allows you to create a Restcomm profile that can be used for P2P or B2BUA calls. This will be empty until you create a new client. You can create a new client by clicking on the Resgister SIP Clent button. + +image:./images/restcomm-admin-ui-6.png[restcomm-admin-ui-6,width=248,height=300] + +*SIP Clients* + +[cols=",",options="header",] +|===================================================================================================================================== +|Number |Description +|1 |The client name. (ex. alice or bob) +|2 |The password that will be used to when you want to register the client with restcomm +|3 |Use to open optional parameters windows +|4 |This can be the full name of the client (ex.Alice Wilkinson) or any descriptive name +|5 |This is where you specify the VoiceUrl that is automatically invoked when the client is called. See the REST API for more details. +|6 |See the REST API for more details. +|7 |This will validate your changes and create the client. +|===================================================================================================================================== + += Outgoing CallerId + +Will be available in future release + +[[logs]] += Logs + +The log section gives you an overview of current Restcomm system information. + +[[logs---calls]] +== Logs - Calls + +A list of all calls that have been processed by Restcomm + +image:./images/restcomm-admin-ui-7.png[restcomm-admin-ui-7,width=300,height=121] + +[[logs---messages]] +== Logs - Messages + +A list of all SMS messages that have been processed by Restcomm + +image:./images/restcomm-admin-ui-8.png[restcomm-admin-ui-8,width=300,height=124] + +[[logs---recordings]] +== Logs - Recordings + +A list of all Recordings (using the Record Verb) that have been processed by Restcomm + +image:./images/restcomm-admin-ui-9.png[restcomm-admin-ui-9,width=300,height=123] + +[[logs---transcriptions]] +== Logs - Transcriptions + +A list of all Transcriptions that have (using the Transcribe parameters of the Record Verb) that have been processed by Restcomm. + +image:./images/restcomm-admin-ui-10.png[restcomm-admin-ui-10,width=404,height=163] + +[[logs---notifications]] +== Logs - Notifications + +A list of all Notifications received by Restcomm. + +image:./images/restcomm-admin-ui-11.png[restcomm-admin-ui-11,width=300,height=122] diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-1.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-1.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-1.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-1.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-10.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-10.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-10.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-10.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-11.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-11.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-11.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-11.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-12.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-12.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-12.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-12.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-2.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-2.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-2.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-2.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-3.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-3.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-3.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-3.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-4.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-4.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-4.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-4.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-5.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-5.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-5.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-5.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-6.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-6.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-6.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-6.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-7.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-7.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-7.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-7.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-8.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-8.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-8.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-8.png diff --git a/restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-9.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-9.png similarity index 100% rename from restcomm/restcomm.docs/sources/src/main/resources/en-US/images/restcomm-admin-ui-9.png rename to restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/images/restcomm-admin-ui-9.png diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/index.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/index.adoc new file mode 100644 index 0000000000..82b641010c --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/admin/index.adoc @@ -0,0 +1,15 @@ += Restcomm Administration Interface + +The Restcomm Administration Interface allows you to interact visually instead of using the following REST APIs below. +Please read <> for understanding how to interact with the Restcomm platform +//// +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +//// diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/Restcomm - Multi-tenancy and Managing Sub-Accounts.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/Restcomm - Multi-tenancy and Managing Sub-Accounts.adoc new file mode 100644 index 0000000000..6020695ab7 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/Restcomm - Multi-tenancy and Managing Sub-Accounts.adoc @@ -0,0 +1,59 @@ +In our continuous effort to improve Restcomm functionalities, we have introduced multi-tenancy as part of http://www.telestax.com/telscale-restcomm-7-4-0-ga-released/[Restcomm 7.4.0]. Multi tenancy support provides a set of rules that improve user information management and control who can gain access to specific accounts. This set of rules will be also applied by the upcoming OAuth support, so they both OAuth and Multi-tenancy Support will handle this consistency together. The information below will provide an overview of how multi-tenancy is applied to Restcomm. + +[[restcomm-rest-api]] +*Restcomm REST API* +~~~~~~~~~~~~~~~~~~~ + +Restcomm REST API access control is managed by two main entities, credentials and accounts. To better understand how it works, we'll assume the following diagram as the account hierarchy, where each account and sub account has its own information. + +image:./images/ElementTree-4.png[ElementTree-4,width=656,height=322] + +Considering that Primary and Secondary accounts represents different Restcomm users, they will not be able to manage information from each other. So if Primary Account tries to access the REST API using its own credentials but requesting for the list of DIDs of the Secondary Account, the response will be a HTTP 401 error. The 'curl' command below represents the given situation. + +[source,lang:default,decode:true] +---- +curl -X GET http://[primarySid]:[primaryAuthToken]@127.0.0.1:8080/restcomm/2012-04-24/Accounts/[secondarySid]/IncomingPhoneNumbers.json +---- + +As mentioned above, there are more possible combinations between credentials and accounts used to request information through the API. But instead list all those possibilities, we can assume the pattern used by the API to control access in a general way, grouped by the result obtained from the API: + +*Allowed:* + +* Request information about the same account used as credential +* Request information about a sub account of the account used as credential + +*Denied:* + +* Request information about the parent account of the account used as credential +* Request information about a account of the same level of the account used as credential +* Request information about a sub account different than the ones from the account used as credential + +This access control is applied to the API's: <>, <>, <>, <>, OutgoingCallerIds, <>, <> and <>. + +To understand this rules based on the hierarchy presented by the diagram above, we can assume the following for each account: + +* *Primary Account* can view and manage Primary Application, DID P, DID A and DID B only. +* *Subaccount A* can view and manage Application A and DID A only. +* *Subaccount B* can view and manage Application B and DID B only. +* *Secondary Account* can view and manage Application S, DID S, DID C and DID D only. +* *Subaccount C* can view and manage Application C and DID C only. +* *Subaccount D* can view and manage Application D and DID D only. + +IMPORTANT: The Applications API has a different access control, and allows the accounts to manage its own applications only. So, if a request is made to this API using a credential different than the account, the response will be a HTTP 401 error. + +[[restcomm-admin-ui]] +*Restcomm Admin UI* +~~~~~~~~~~~~~~~~~~~ + +The user interface follows a similar behaviour to the API. Is known that the AdminUI currently shows only info related to the logged user, but now the local applications displayed under the 'Restcomm Apps' option were adjusted to follow the same behaviour. This filter is also applied to the available applications when configuring a DID, as shown by the images below. + +[Available applications at DID's configuration, filtered by logged user] +image:./images/Screen-Shot-2015-10-05-at-16.40.46.png[Screen Shot 2015-10-05 at 16.40.46,width=525,height=351] + +[Restcomm Apps list, filtered by logged user.] +image:./images/Screen-Shot-2015-10-05-at-16.35.37.png[Screen Shot 2015-10-05 at 16.35.37,width=506,height=332] + +[RVD Projects created by the user] +image:./images/Screen-Shot-2015-10-05-at-16.34.53.png[Screen Shot 2015-10-05 at 16.34.53,width=512,height=396] + +This is the way that multi tenancy support provides access control between accounts, ensuring that only authorized accounts will be able to see and manage another accounts info.   diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/account-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/account-api.adoc new file mode 100644 index 0000000000..016817c566 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/account-api.adoc @@ -0,0 +1,283 @@ += Restcomm API – Account + +[[Accounts]] +== Accounts + +Accounts and sub-accounts are useful for things like segmenting phone numbers and usage data for your users and controlling access to data. + +=== Account Resource URI + +*/2012-04-24/Accounts/\{AccountSid}* + +=== Resource Properties + +[cols=",",options="header",] +|========================================================================================================================= +|Property |Description +|Sid |A string that uniquely identifies this account. +|DateCreated |The date that this account was created. +|DateUpdated |The date that this account was last updated. +|FriendlyName |A description of this account, up to 64 characters long. By default the FriendlyName is your email address. +|Status |The status of this account. Possible values are active, suspended, and closed. +|AuthToken |The authorization token for this account. This should not be shared. +|Uri |The URI for this account, relative to https://localhost:port/restcomm. +|========================================================================================================================= + +=== Supported Operations + +*HTTP GET.* Returns the representation of an Account resource, including the properties above. + +* Account Resource URI. */2012-04-24/Accounts/\{EmailAddress}* + +**HTTP POST/PUT**. Modifies an Account resource and returns the representation, including the properties above. Below you will find a list of optional parameters. + +==== Request Parameters + +[cols=",",options="header",] +|============================================================================================== +|Parameter |Description +|FriendlyName |A description of this account, up to 64 characters long. +|Status |The status of this account. Possible values are active, suspended, and closed. +|Password |A password that will be used to generate the AuthToken for the new Account resource. +|============================================================================================== + +=== Account Status transitions + +When the Status of an account is modified by invoking the POST method, different +business constraints will be applied: + + +* The given Status will be applied to the given Account, and all the subaccount +tree. + +=== Uninitialized Account Status +The following conditions will be honored for an Uninitialized account: + +* When a new account is created, this Status is the default. +* An Uninitialized account will reject its Credentials to be used for any REST API invocation. +* An Uninitialized account will reject any Voice/SMS/USSD traffic. In addition, any +client registration related to the account, will be rejected. +* To activate an uninitialized account, a password reset is necessary. + +=== Active Account Status +The following conditions will be honored for an Active account: + +* An Active account will allow its Credentials to be used for any REST API invocation. +* An Active account will allow any Voice/SMS/USSD traffic. In addition, any +client registration related to the account, will be allowed. + +=== Suspended Account Status +The following conditions will be honored for a suspended account: + +* A Suspended account will reject its Credentials to be used for any REST API invocation. +* A Suspended account will reject any Voice/SMS/USSD traffic. In addition, any +client registration related to the accoutn, will be rejected. +* A Suspended accounts may be reactivate by changing the Status to Active again. + +=== Closed Account Status +The following conditions will be honored for a Closed account: + +* A Closed account will reject its Credentials to be used for any REST API invocation. +* A Closed account will reject any Voice/SMS/USSD traffic. In addition, any +client registration related to the accoutn, will be rejected. +* When an account is closed, all related resources are removed. +* Any modification over a Closed account will be rejected. This means a closed +account can't be reactivated + +=== Account Migration to new Organization + +Account Migration operation can be used to migrate a top level account to a new organization. +In the process, all child accounts will also be migrated. + +* Account Migration Resource URI */2012-04-24/Accounts/migrate/\{AccountSid}* +* Method *HTTP POST* +* The operation is allowed for Super Admin only +* The account to migrate must be a top level account (child of Super Admin) + +==== Request Parameters +[cols=",",options="header",] +|============================================================================================== +|Parameter |Description +|Organization |The new Organization SID or Domain Name to move the account. *Required* +|============================================================================================== + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|200 OK |Migration operation completed successfully +|403 Forbidden |Only Super Admin is allowed for the migrate operation +|412 Precondition Failed |Target Organization SID or Domain Name is missing +|404 Not Found |Target Account SID is missing +|400 Bad Request |Target Account is not a top level account or target account is already in the new organization +|============================================================================================== + +**Get information about the default account.** + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf +.... + + +**Change default account password(AuthToken).** + +To update an account you need to provide the SID of the account or the email address of the account (make sure you url escape the @ sign of the email address) + +For example, update password using account sid: +.... +curl -X PUT https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf -d "Password=NewPassword" +.... + +And update password using email address of the account: + +.... +curl -X PUT https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/administrator%40company.com -d "Password=NewPassword" +.... + +NOTE: The above command uses the Account SID of the requestor, and the one below uses the Email Account. Note the administrator%40company.com is used instead of administrator@company.com . This is because using curl on the bash terminal doesn't parse the @ correctlyl. If you were to running on a browser, you can safely use the @ as the web browser will correctly handle it. + +.... +curl -X GET https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf +.... + +The above commands will print an output similar to the one below: + +---- + + + ACae6e420f425248d6a26948c17a9e2acf + Default Administrator Account + active + Full + 2012-04-24T00:00:00.000-06:00 + 2012-04-24T00:00:00.000-06:00 + 77f8c12cc7b8f8423e5c38b035249166 + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf + + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/AvailablePhoneNumbers + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Conferences + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/OutgoingCallerIds + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Sandbox + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions + + +---- + +[[Accounts_List]] +== Account List Resource + +* Account List Resource URI. */2012-04-24/Accounts* + +=== Supported Operations + +**HTTP GET**. Returns the list representation of all the *Sub-Account* resources for this **Account**, including the properties above. + +**HTTP POST**. Creates a new Sub-Account and returns the representation of the Sub-Account resource, including the properties above. Below you will find a list of required and optional parameters.   + +=== Request Parameters + +[cols=",",options="header",] +|============================================================================================================================================================================================================================== +|Parameter |Description +|EmailAddress(Required) |The email address to use for this account. +|FriendlyName |A description of this account, up to 64 characters long. Default, is your email address. +|Status |The status of this account. Default is active, possible values are active, suspended, and closed. +|Password(Required) |A password that will be used to generate the AuthToken for the new Account resource. +|Role(Required) |The security role that this Account resource will use. If no role is provided then the role of the account resource creating this will be inherited to the new Account resource and may compromise the system. +|OrganizationSid |Sid of organization, in case you want to create this account under a different account than its parent account. By default each new account will inherit its parent's organization. Please note only Super Admins have right to create an account under a different organization. +|============================================================================================================================================================================================================================== + + +[[sub-accounts]] +== Sub-Accounts + +You can read more about Sub-Accounts and Multi-tenancy http://docs.telestax.com/restcomm-multi-tenancy-and-managing-sub-accounts/[HERE] + + +---- +curl -X GET https://[primarySid]:[primaryAuthToken]@127.0.0.1:8080/restcomm/2012-04-24/Accounts/[secondarySid]/ +---- + +=== Get a list of all current accounts + +---- +curl -X GET https://[primarySid]:[primaryAuthToken]@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ +---- + +Here is an example of how to create a **sub-account**. The sub-account will inherit the same permissions has the Administrator's account. + +.... +curl -X POST https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ -d "FriendlyName=MySubAccount" -d "EmailAddress=test@telestax.com" -d "Password=restcomm" +.... + +Here is an example of creating an account under a specific organization. + +.... +curl -X POST https://:@/restcomm/2012-04-24/Accounts/ -d "FriendlyName=MySubAccount" -d "EmailAddress=test@telestax.com" -d "Password=restcomm" -d "OrganizationSid=" +.... + + +=== Supported Operations + +NOTE: the **SID**, Email and the *AuthToken* (see output below) of the sub-account can now be used instead of the Administrator's account   + +---- + + + AC3b8f0dd2e5026abde018446cbb3b185d + MySubAccount + active + Full + 2013-10-16T09:22:28.708-06:00 + 2013-10-16T09:22:28.712-06:00 + 53134d7a9914e2b47c8435ebdb50ded3 + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d + + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/AvailablePhoneNumbers + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Calls + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Conferences + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/IncomingPhoneNumbers + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Notifications + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/OutgoingCallerIds + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Recordings + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Sandbox + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/SMS/Messages + /2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d/Transcriptions + + +---- + +[[close-sub-accounts]] +=== Close Sub-Accounts + +.JSON Account Closing +---- +curl -X PUT https://ACae6e420f425248d6a26948c17a9e2acf:PWD@127.0.0.1:8080/restcomm/2012-04-24/Accounts.json/AC3b8f0dd2e5026abde018446cbb3b185d -d "Status=closed" +---- + +.XML Account Closing +---- +curl -X PUT https://ACae6e420f425248d6a26948c17a9e2acf:PWD@127.0.0.1:8080/restcomm/2012-04-24/Accounts/AC3b8f0dd2e5026abde018446cbb3b185d -d "Status=closed" +---- + +The command above will close an account permanently. When an account is closed access to the system through it is revoked and most of its resources are deleted. The actual account entity will remain present though. + +[[delete-sub-accounts]] +=== Delete Sub-Accounts (deprecated) + +.XML Account Deletion +---- +curl -X DELETE https://ACae6e420f425248d6a26948c17a9e2acf:PWD@192.168.1.3:8080/restcomm/2012-04-24/Accounts/ +---- + +.JSON Account Deletion +---- +curl -X DELETE https://ACae6e420f425248d6a26948c17a9e2acf:PWD@192.168.1.3:8080/restcomm/2012-04-24/Accounts.json/.json +---- + +NOTE: Account deletion has been deprecated from the REST API. Both of these methods will return HTTP 405. You will need to **close** the account instead. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/applications-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/applications-api.adoc new file mode 100644 index 0000000000..035cc5418e --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/applications-api.adoc @@ -0,0 +1,195 @@ += Restcomm API – Applications + +[[applications]] +== Applications + +An Application instance resource represents a RCML set of instructions used by a RestComm interpreter to process an on-going call, SMS or USSD. + +RestComm stores only part of the metadata for this Application, which contains as one of its attributes the URL with the address of the application server where the RCML can be retrieved. + +Currently there are 3 types of Applications that are supported: Voice, SMS and USSD. Each type of Application will be used by its specific interpreter. + +Considering the access control executed by multi-tenancy, each Application can be created, read, updated or deleted by its owner solely. Any attempt of access to an Application using an account different than its owner will be denied. + +=== Applications Resource URI + +*2012-04-24/Accounts/\{AccountSid}/Applications/\{ApplicationSid}* + +=== Resource Properties + +[cols=",",] +|========================================================================================================= +|PROPERTY |DESCRIPTION +|Sid |A string that uniquely identifies this Application. +|DateCreated |The date when this Application was created. +|DateUpdated |The date wher this Application was last updated. +|FriendlyName |A friendly name for this Application. +|AccountSid |The unique ID of the Account that owns this Application. +|ApiVersion |Version of the API applied to this Application. +|HasVoiceCallerIdLookup |Look up the caller’s caller-ID name from the CNAM database. Either true or false. +|Uri |The URI for this Application, relative to https://localhost:port/restcomm. +|RcmlUrl |The HTTP address that RestComm will use to get the RCML of this Application. +|Kind |The kind of this Application. (Supported values: voice, sms or ussd) +|========================================================================================================= + +=== Supported Operations + +*HTTP GET* Returns the representation of an Application resource, including the properties described on the table "Resource Properties". + +*HTTP POST and PUT*   Modifies an Application resource and returns the representation, including the properties described on the table "Resource Properties". The table below describes a list of optional parameters. + +==== Request Parameters + +You may specify one or more of the following parameters to update this Application’s respective properties: + +[cols=",",] +|====================================================================================================== +|PROPERTY |DESCRIPTION +|FriendlyName |A friendly name for this Application. +|VoiceCallerIdLookup |Look up the caller’s caller-ID name from the CNAM database. Either true or false. +|RcmlUrl |The HTTP address that RestComm will use to get the RCML of this Application. +|Kind |The kind of this Application. (Supported values: voice, sms or ussd) +|====================================================================================================== + +*HTTP DELETE* + +Remove the Application from RestComm's database. This Application will not be displayed anymore at the list of available applications while using AdminUI, consequently, not possible to be assigned to a RestComm Number or Client. If successful, returns an HTTP 204 response with no body. + +== Applications List + +=== Applications List Resource URI + +*2012-04-24/Accounts/\{AccountSid}/Applications* + +=== Supported Operations + +*HTTP GET* Returns a list of Applications resource representations, each representing a application given to your account. + +*List Filters* Given the rules of multi-tenancy, the list of applications is automatically filtered using the informed account to authenticate, returning all the applications owned by this account. No additional filters are currently supported. + +*HTTP POST* Create a new Application resource with the information provided by the required and optional parameters described by the tables below. + +=== Required Parameters + +Your request must include exactly the following parameters: + +[cols=",",] +|=================================================== +|PROPERTY |DESCRIPTION +|FriendlyName |A friendly name for this Application. +|=================================================== + +=== Optional Parameters + +Your request may include the following parameters: + +[cols=",",] +|========================================================================================================= +|PROPERTY |DESCRIPTION +|ApiVersion |Version of the API applied to this Application. +|HasVoiceCallerIdLookup |Look up the caller’s caller-ID name from the CNAM database. Either true or false. +|RcmlUrl |The HTTP address that RestComm will use to get the RCML of this Application. +|Kind |The kind of this Application. (Supported values: voice, sms or ussd) +|========================================================================================================= + +*HTTP PUT* Not supported. + +*HTTP DELETE* Not supported. + +== Create an Application + + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acf:f8b593f84593130c39700c11ee996c0e@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications -d "FriendlyName=Application FooBar" -d "ApiVersion=2012-04-24" -d "HasVoiceCallerIdLookup=false" -d "RcmlUrl=http://127.0.0.1:8080/restcomm-rvd/services/apps/foobar/controller" -d "Kind=voice" +---- + +The output of the command will be similar to the one below + +[source,lang:xhtml,decode:true] +---- + + + APdc46145309d14e97b62230cd3f269ed4 + Wed, 27 Jan 2016 11:23:54 -0200 + Wed, 27 Jan 2016 11:23:54 -0200 + Application FooBar + ACae6e420f425248d6a26948c17a9e2acf + 2012-04-24 + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APdc46145309d14e97b62230cd3f269ed4 + http://127.0.0.1:8080/restcomm-rvd/services/apps/foobar/controller + voice + + +---- + +== Update a Application + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acf:f8b593f84593130c39700c11ee996c0e@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APdc46145309d14e97b62230cd3f269ed4 -d "FriendlyName=Application X" +---- + +The output of the command will be similar to the one below + +[source,lang:xhtml,decode:true] +---- + + + APdc46145309d14e97b62230cd3f269ed4 + Wed, 27 Jan 2016 11:23:54 -0200 + Wed, 27 Jan 2016 12:50:18 -0200 + Application X + ACae6e420f425248d6a26948c17a9e2acf + 2012-04-24 + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APdc46145309d14e97b62230cd3f269ed4 + http://127.0.0.1:8080/restcomm-rvd/services/apps/foobar/controller + voice + + +---- + +== Delete a Application + +---- +curl -X DELETE http://ACae6e420f425248d6a26948c17a9e2acf:f8b593f84593130c39700c11ee996c0e@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/APdc46145309d14e97b62230cd3f269ed4 +---- + +No output for DELETE operation. + +Get a List of available Applications + +---- +curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:f8b593f84593130c39700c11ee996c0e@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications.json +---- + +The output of the command will be similar to the one below + +---- +[ + { + "sid": "AP73926e7113fa4d95981aa96b76eca854", + "date_created": "Wed, 23 Sep 2015 06:56:04 -0300", + "date_updated": "Wed, 23 Sep 2015 06:56:04 -0300", + "friendly_name": "rvdCollectVerbDemo", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "api_version": "2012-04-24", + "voice_caller_id_lookup": false, + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854.json", + "rcml_url": "/restcomm-rvd/services/apps/PR7addb947898443329cf50913103f77a2/controller", + "kind": "voice" + }, + { + "sid": "AP81cf45088cba4abcac1261385916d582", + "date_created": "Wed, 23 Sep 2015 06:56:17 -0300", + "date_updated": "Wed, 23 Sep 2015 06:56:17 -0300", + "friendly_name": "rvdESDemo", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "api_version": "2012-04-24", + "voice_caller_id_lookup": false, + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP81cf45088cba4abcac1261385916d582.json", + "rcml_url": "/restcomm-rvd/services/apps/PR2cbed2a2a56947cdbeaa8b0af8a6c02d/controller", + "kind": "voice" + } + ] +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/available-phone-numbers-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/available-phone-numbers-api.adoc new file mode 100644 index 0000000000..c2e46cee7b --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/available-phone-numbers-api.adoc @@ -0,0 +1,173 @@ += Restcomm API – Available Phone Numbers + +== AvailablePhoneNumbers + +The *AvailablePhoneNumbers* subresources let you search for incoming local and toll-free phone numbers that are available for you to purchase from a Telestax partner. *AvailablePhoneNumbers* List Resource URI. */2012-04-24/Accounts/\{AccountSid}/AvailablePhoneNumbers/US/Local* Searching For Numbers. When using RestComm the way to search for new phone numbers is by searching the *AvailablePhoneNumbers* list resource and providing the desired area code as a filter. + +=== Resource Properties + +The following properties are available for phone numbers from the US and Canada: + +[cols=",",options="header",] +|=============================================================================================================================================================================================================================== +|Property |Description +|FriendlyName |A nicely-formatted version of the phone number. +|PhoneNumber |The phone number, in E.164 (i.e. "+1") format. +|Lata |The LATA of this phone number. +|RateCenter |The rate center of this phone number. +|Latitude |The latitude coordinate of this phone number. +|Longitude |The longitude coordinate of this phone number. +|Region |The two-letter state or province abbreviation of this phone number. +|PostalCode |The postal (zip) code of this phone number. +|IsoCountry |The http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2[ISO country code] of this phone number. +|Capabilities |This is a set of boolean properties that indicate whether a phone number can receive calls or messages. Possible capabilities are `Voice`, `SMS`, and `MMS` with each having a value of either `true` or `false`. +|=============================================================================================================================================================================================================================== + +The following properties are available for phone numbers outside the US and Canada: + +[cols=",",options="header",] +|================================================================================================================================================================================================================================================= +|Property |Description +|FriendlyName |A nicely-formatted version of the phone number. +|PhoneNumber |The phone number, in [E.164] (i.e. "+44") format. +|IsoCountry |The http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2[ISO country code] of this phone number. +|Capabilities |This is a set of boolean properties that indicate whether a phone number can receive calls or messages. Possible capabilities are `Voice`, `SMS`, and `MMS` with each having a value of either `true` or `false`. +|================================================================================================================================================================================================================================================= + +[[address-requirement-values]] +=== Address Requirement Values + +The following are the possible values for the `address_required` property. + +[cols=",",options="header",] +|============================================================================== +|Status |Description +|none |An Address is not required for this phone number. +|any |Your account must have an Address, but it can be anywhere in the world. +|local |Your account must have an Address within the phone number's country. +|foreign |Your account must have an Address outside the phone number's country. +|============================================================================== + +[[toll-free-instance]] +== AvailablePhoneNumber Toll-Free Instance Resource + +Some DID providers allow toll-free numbers from the US, Canada, and the UK. + +[[toll-free-instance-uri]] +=== Resource URI + +An AvailablePhoneNumber toll-free instance resource has no URI. You cannot make requests directly to AvailablePhoneNumber instance resources. Instead, make a request to the toll-free list subresource and then choose a number from the list. + +[[toll-free-instance-properties]] +=== Resource Properties + +[cols=",",options="header",] +|=============================================================================================================================================================================================================================== +|Property |Description +|FriendlyName |A nicely-formatted version of the phone number. +|PhoneNumber |The phone number, in E.164 (i.e. "+1") format. +|IsoCountry |The http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2[ISO country code] of this phone number. +|Capabilities |This is a set of boolean properties that indicate whether a phone number can receive calls or messages. Possible capabilities are `Voice`, `SMS`, and `MMS` with each having a value of either `true` or `false`. +|AddressRequirements |This indicates whether the phone number requires you or your customer to have an Address registered with Restcomm. Possible values are `none`, `any`, `local`, or `foreign`. +|=============================================================================================================================================================================================================================== + +[[mobile-instance]] +== AvailablePhoneNumber Mobile Instance Resource + +[[toll-free-instance-uri]] +=== Resource URI + +An AvailablePhoneNumber mobile instance resource has no URI. You cannot make requests directly to AvailablePhoneNumber instance resources. Instead, make a request to the mobile list subresource and then choose a number from the list. + +[[mobile-instance-properties]] +=== Resource Properties + +[cols=",",options="header",] +|=============================================================================================================================================================================================================================== +|Property |Description +|FriendlyName |A nicely-formatted version of the phone number. +|PhoneNumber |The phone number, in E.164 (i.e. "+1") format. +|IsoCountry |The http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2[ISO country code] of this phone number. +|Capabilities |This is a set of boolean properties that indicate whether a phone number can receive calls or messages. Possible capabilities are `Voice`, `SMS`, and `MMS` with each having a value of either `true` or `false`. +|AddressRequirements |This indicates whether the phone number requires you or your customer to have an Address registered with Restcomm. Possible values are `none`, `any`, `local`, or `foreign`. +|=============================================================================================================================================================================================================================== + +[[local]] +== AvailablePhoneNumbers Local List Subresource + +[[local-uri]] +=== Resource URI + +---- +/2012-04-24//Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/Local +---- + +\{IsoCountryCode} is a country code in ISO 3166-1 alpha-2 format. For example, the IsoCountryCode for Canada is `CA`. See Supported Countries for a full list of countries and IsoCountryCodes supported by Restcomm. + +[[local-get]] +=== HTTP GET + +Returns a list of local AvailablePhoneNumber resource representations that match the specified filters, each representing a phone number that is currently available for provisioning within your account. + +[[local-get-basic-filters]] +=== Basic List Filters + +The following basic GET query string parameters allow you to filter the list of numbers returned by Restcomm. Note, parameters are case-sensitive. + +[cols=",",options="header",] +|=============================================================================================================================================================================================================================================================================== +|Parameter |Description +|AreaCode |Find phone numbers in the specified area code. (US and Canada only) +|Contains |A pattern to match phone numbers on. Valid characters are `'*'` and `[0-9a-zA-Z]`. The `'*'` character will match any single digit. +|SmsEnabled |This indicates whether the phone numbers can receive text messages. Possible values are `true` or `false`. +|MmsEnabled |This indicates whether the phone numbers can receive MMS messages. Possible values are `true` or `false`. +|VoiceEnabled |This indicates whether the phone numbers can receive calls. Possible values are `true` or `false`. +|ExcludeAllAddressRequired |Indicates whether the response includes phone numbers which require any Address. Possible values are `true` or `false`. If not specified, the default is `false`, and results could include phone numbers with an Address required. +|ExcludeLocalAddressRequired |Indicates whether the response includes phone numbers which require a local Address. Possible values are `true` or `false`. If not specified, the default is `false`, and results could include phone numbers with a local Address required. +|ExcludeForeignAddressRequired |Indicates whether the response includes phone numbers which require a foreign Address. Possible values are `true` or `false`. If not specified, the default is `false`, and results could include phone numbers with a foreign Address required. +|Beta |Include phone numbers new to theRestcomm platform. Possible values are either `true` or `false`. Default is `true`. +|=============================================================================================================================================================================================================================================================================== + +=== Supported Operations + +==== HTTP GET. + +Returns the representation of an *AvailablePhoneNumber* resource, including the properties above. + +===== Request Parameters + +[cols=",",options="header",] +|================================================= +|Property |Description +|AreaCode |A three digit area code inside the U.S. +|================================================= + +== Querying Available Phone Numbers + +NOTE: You need to be using Restcomm Cloud or setup the DID Provider in Restcomm in order to be able to use this feature. See the Tutorial section. + +Here is an example, the *AreaCode* is any valid United States Code + +.... +curl -G http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/AvailablePhoneNumbers/US/Local -d "AreaCode=305" +.... + +The *AvailablePhoneNumbers* subresources let you search for incoming local and toll-free phone numbers that are available for you to purchase from a Telestax partner. + +* AvailablePhoneNumbers List Resource URI. /**2012-04-24/Accounts/\{AccountSid}/AvailablePhoneNumbers/US/Local** + +Searching For Numbers. When using Restcomm the way to search for new phone numbers is by searching the *AvailablePhoneNumbers* list resource and providing the desired area code as a filter. + +=== Supported Operations + +==== HTTP GET + +Returns the representation of an *AvailablePhoneNumber* resource, including the properties above. + +==== Request Parameters + +[cols=",",options="header",] +|================================================= +|Property |Description +|AreaCode |A three digit area code inside the U.S. +|================================================= diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/calls-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/calls-api.adoc new file mode 100644 index 0000000000..1fcc523243 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/calls-api.adoc @@ -0,0 +1,567 @@ += Restcomm API – Calls + +== Calls + +A *Call* represents a connection between a phone or user agent and RestComm. This may be inbound or outbound. The Calls list resource represents the set of phone calls originated and terminated from an account. + +=== Call Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Calls/\{CallSid}* + +=== Resource Properties + +[cols=",",options="header",] +|====================================================================================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this call. +|ParentCallSid |A string that uniquely identifies the call that created this leg. +|DateCreated |The date that this call was created. +|DateUpdated |The date that this call was last updated. +|AccountSid |The unique id of the Account that created this call. +|To |The phone number or identifier that will be the recipient of this call. +|From |The phone number or identifier that originated this call. +|PhoneNumberSid |If the call was inbound, this is the Sid of the IncomingPhoneNumber that received the call. +|Status |A string representing the status of the call. Possible values are queued, ringing, in-progress, completed, failed, busy and no-answer. +|StartTime |The start time of the call. Empty if the call has not yet been started. +|EndTime |The end time of the call. Empty if the call has not ended.. +|Duration |The length of the call in seconds. +|Price |The charge for this call, in the currency associated with the account. Populated after the call is completed. +|Direction |A string describing the direction of the call. Possible values are inbound, outbound-api, and outbound-dial +|AnsweredBy |If this call was initiated with answering machine detection, either human or machine. Empty otherwise. +|ApiVersion |Displays the current API version +|ForwardFrom |If this call was an incoming call forwarded from another number, the forwarding phone number (depends on carrier supporting forwarding). Empty otherwise. +|CallerName |If this call was an incoming call, the caller's name. Empty otherwise. +|Uri |The URI for this account, relative to https://localhost:port/restcomm. +|====================================================================================================================================================================== + +=== Supported Operations +**HTTP GET**. Returns the representation of a Call resource, including the properties above. + +== Call List Resource URI + +**/2012-04-24/Accounts/\{AccountSid}/Calls** + +=== Supported Operations +**HTTP GET**. Returns the list representation of all the Call resources for this Account, including the properties above. + +**HTTP POST**. Makes a new Call and returns the representation of the Call resource, including the properties above. Below you will find a list of required and optional parameters.   + +=== Request Parameters + +[cols=",",options="header",] +|========================================================================================================================================== +|Parameter |Description +|From(Required) |The phone number to use as the caller id. +|To(Required) |The phone number to call. +|Url(Required) |The fully qualified URL that should be executed when the call connects. +|Method |The HTTP method RestComm should use when making its request to the above Url. Defaults to POST. +|FallbackUrl |The URL that RestComm will request if execution of Url fails for any reason. +|FallbackMethod |The HTTP method that RestComm should use to request the FallbackUrl. Must be either GET or POST. Defaults to POST. +|statusCallbackEvent |`initiated`, `ringing`, `answered`, `completed`. Default none +|statusCallback |any url. Default none +|statusCallbackMethod |`GET`, `POST`. Default `POST` +|Timeout |The number of seconds that RestComm should allow the phone to ring before assuming there is no answer. The default is 60 seconds. +|========================================================================================================================================== + +==== statusCallbackEvent + +When creating a Call using the Calls API, an outbound call is initiated. The call transitions from the initiated state to the ringing state when the phone starts ringing. It transitions to the answered state when the call is picked up, and finally to the completed state when the call is over. With **statusCallbackEvent**, you can subscribe to receive webhooks for the different call progress events: initiated, ringing, answered, or completed for a given call. + +The *statusCallbackEvent* attribute allows you to specify which events Restcomm should webhook on. To specify multiple events separate them with a space: initiated ringing answered completed. If a statusCallback is provided and no status callback events are specified the completed event will be sent by default. + +image::images/status-callback-events-dial.png[Outbound Dial call events diagram] + +[cols=",",options="header",] +|============================================================================================================================================================================================================================================================== +|Event |Description +|initiated |The `initiated` event is fired when Restcomm starts dialing the call. +|ringing |The `ringing` event is fired when the call starts ringing. +|answered |The `answered` event is fired when the call is answered. +|completed |The `completed` event is fired when the call is completed regardless of the termination status: `busy`, `canceled`, `completed`, `failed`, or `no-answer`. If no `statusCallbackEvent` is specified, `completed` will be fired by default. +|============================================================================================================================================================================================================================================================== + +[[attributes-status-callback]] +==== statusCallback + +The *statusCallback* attribute allows you to specify a URL for Restcomm to send webhook requests to on each event specified in the statusCallbackEvent attribute. + +==== statusCallbackMethod + +The *statusCallbackMethod* attribute allows you to specify which HTTP method Restcomm should use when requesting the URL in the statusCallback attribute. The default is POST. + +==== Status Callback HTTP Parameters + +The parameters Restcomm passes to your application in its asynchronous request to the StatusCallback URL include all parameters passed in a synchronous request to retrieve RCML when Restcomm receives a call to one of your Restcomm numbers. The full list of parameters and descriptions of each are in the RCML Voice Request documentation. + +When the call progress events are fired, the Status Callback request also passes these additional parameters: + +[cols=",",options="header",] +|=================================================================================================================================================================================================================================================================== +|Parameter |Description +|CallSid |A unique identifier for this call, generated by Restcomm. You can use the `CallSid` to modify the child call by POSTing to Calls/\{CallSid} with a new RCML URL. +|CallStatus |A descriptive status for the call. The value is one of **`queued`**, **`initiated`**, **`ringing`**, **`in-progress`**, **`busy`**, **`failed`**, or **`no-answer`**. See the CallStatus section for more details. +|CallDuration |The duration in seconds of the just-completed call. Only present in the `completed` event. +//|RecordingUrl |The URL of the phone call's recorded //audio. This parameter is included only if //*`Record=true`* is set on the REST API request and //does not include recordings from `` or //``. *`RecordingUrl`* is only present in the //`completed` event. +//|RecordingSid |The unique ID of the Recording from //this call. `RecordingSid` is only present in the //`completed` event. +//|RecordingDuration |The duration of the recorded //audio (in seconds). `RecordingDuration` is only //present in the `completed` event. +|Timestamp |The timestamp when the event was fired, given as UTC in http://php.net/manual/en/class.datetime.php#datetime.constants.rfc2822[RFC 2822] format. +|CallbackSource |A string that describes the source of the webhook. This is provided to help disambiguate why the webhook was made. On Status Callbacks, this value is always *`call-progress-events`.* +|SequenceNumber |The order in which the events were fired, starting from `0`. Although events are fired in order, they are made as separate HTTP requests and there is no guarantee they will arrive in the same order. +|=================================================================================================================================================================================================================================================================== + +== Making a call to a SIP account + +Restcomm will make a call to any SIP account that is reachable. It the example below, the *SIP* account is listening on port **5060**. When you make the call, the SIP phone on which Alice is registered will ring and the hello-play.xml file will be played. + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json -d "From=+16175551212" -d "To=sip:alice@127.0.0.1:5060" -d "Url=http://127.0.0.1:8080/restcomm/demos/hello-play.xml" +.... + +== Making a call to a Restcomm client + +You must first create a RestComm client. In the example below, the Restcomm client created is called Alice. When you make the call, the SIP phone on which Alice is registered will ring and the *hello-play.xml* file will be played. + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json -d "From=+16175551212" -d "To=client:alice" -d "Url=http://127.0.0.1:8080/restcomm/demos/hello-play.xml" +.... + +== Calling a DID number + +The above example shows how to make a call to a SIP number. If you want to make a call to a DID number, you must can connect Restcomm to a DID provisioning service provider. The quickest way is to use RestComm AMI on Amazon Cloud. Get a list of all available calls. This will return all the available calls linked to the account SID + +== Working on a production server +Using filter is a good practice on a server with thousands or millions of calls + +.... +curl -X GET https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls +.... + +If the system hasn't received any calls, you will see the the output below + +[source,lang:xml,decode:true] +---- + + +---- + +== Modifying Live Calls +Real time call modification allows you to interrupt an in-progress call and terminate it or have it begin processing *RCML* from a new URL. This is useful for any application where you want to asynchronously change the behavior of a running call. For example: hold music, call queues, transferring calls, forcing hangup, etc. + +*Live Call Modification API is supported only for calls created with Dial verb using a RCML application* + +*HTTP POST* to a Call + +To redirect or terminate a live call, you make an *HTTP POST* request to an in­-progress Call instance resource URI: + +*/2012­04­24/Accounts/\{AccountSid}/Calls/\{CallSid}* + +or + +*/2012­04­24/Accounts/\{AccountSid}/Calls.json/\{CallSid}* + +The following parameters are available for you to *POST* request when modifying a phone call: + +=== Request Parameters + +[cols=",",options="header",] +|=================================================================================================================================================================================================================================================== +|Parameter |Description +|Url |A valid URL that returns RCMLL. Restcomm will immediately redirect the call to the new RCML. +|Method |The HTTP method Restcomm should use when requesting the above URL. Defaults to POST. +|Status |Either *canceled* or completed. Specifying canceled will attempt to hangup calls that are queued or ringing but not affect calls already in progress. Specifying completed will attempt to hang up a call even if it's already in progress. +| Mute | Either *true* or *flase*. Setting value of this parameter to *true* will mute the call. Setting value of this parameter to *false* will unmute the call. +|=================================================================================================================================================================================================================================================== + +=== Call in-Progress + +Note that any call which is currently ringing within a Dial verb is in-progress from the point of view of Restcomm, and thus you must use '**Status=completed**' to cancel it. + +==== Optional Parameters + +You may *POST* the following parameters: + +==== Request Parameters + +[cols=",",options="header",] +|================================================================================================================================== +|Parameter |Description +|FallbackUrl |A URL that Restcomm will request if an error occurs requesting or executing the RCMLL at Url. +|FallbackMethod |The HTTP method that Restcomm should use to request the FallbackUrl. Must be either GET or POST. Defaults to POST. +|StatusCallback |A URL that Restcomm will request when the call ends to notify your app. +|StatusCallbackMethod |The HTTP method Restcomm should use when requesting the above URL. Defaults to POST. +|MoveConnectedCallLeg |If True, Restcomm will move both call legs to the new URL +|================================================================================================================================== + +=== Description + +Prerequisite for the Live Call Modification API is to know the *CallSid* ​of the call. The **CallSid**​ is generated by Restcomm for every incoming or outgoing call. When we create an outgoing call using the Calls REST API, Restcomm will generate the **CallSid** ​and the response will contain the **CallSid**​. For an Incoming call, Restcomm will generate the **CallSid**​, and will include it in the parameters of the *GET* or *POST* request to download the RCML from the application server. So the application server, will get the *CallSid* ​for this incoming call and can store it for later use. + +[[steps-for-an-incoming-call-are-the-following]] +==== Steps for an incoming call are the following: + +* New incoming call to Restcomm +* Restcomm generates CallSid and other parameters for this call +* Restcomm prepares GET/POST request and attaches the previously prepared parameters +* Restcomm sends the GET/POST request to the URL assigned to the DID called +* Application server receives the GET/POST request +* Application server should store the CallSid along with the rest of the parameters for later use +* Application server prepares the response with the appropriate RCML for the given DID and send it back to Restcomm to process it + +Given that we have the *CallSid* ​available, ​the next step to modify a live call is to prepare the new *POST* request to Restcomm with the URL of the new destination application. + +Lets assume that initially the Application server prepared an RCML that will connect the incoming call to Bob and that later Bob wants this call to be transferred to Alice. Application Server will have to prepare a new RCML that will dial to Alice, and using the Live Call Modification API, will ask Restcomm to process this new RCML for the incoming call and thus will connect it to Alice. + +Here are the steps: + +* Incoming call -­ CallSid (1234567890) +* Applcation server: - Store CallSid and other parameters - Prepare and send RCML that connects the call to Bob (using Dial verb) +* Restcomm process the given RCML and connects incoming call to Bob +* Bob wants to transfer the call to Alice and sends the request to Controller (application server) +* Application server: - Prepares new RCML with a given URL: http://app.server/CallToAlice that using Dial will dial to Alice - Uses Live Call Modification prepares a new POST request: http://RESTCOMM_IP:8080/restcomm/2012­04­24/Accounts/\{AccountSid/Calls/YOUR_CALL_SID - in the POST requests adds the following parameters: Url=http://app.server/CallToAlice +* Restcomm process this Live Call Modification request and redirects the incoming call to the new RCML application (to the new URL) +* Eventually the incoming call will be connected to Alice. + +Similar, application server can change an incoming call to Bob to a conference call where more participants can be added later. Given that application server already knows the CallSid for the incoming call to Bob + +* Will prepare a new RCML for the Dial Conference +* Will prepare new POST Live Call Modification request for the incoming call to be connected to the new url (that will dial to the conference) +* Will then prepare new outgoing call request, using the Calls Rest API that will connect Bob to the conference application URL: - http://RESTCOMM_IP:8080/restcomm/2012­04­24/Accounts/\{AccountSid}/Calls - will pass the following parameters: **From**=INCOMING_CALL_ID **To**=client:bob **Url**=CONFERENCE_APPLICATION_URL +* Later application server can create more outgoing call requests, similar to the one above, to invite other clients or sip URLs or PSTN numbers to this conference call + +[[examples]] +== Examples + +=== Redirect Call to a new RCML +Live Call Modification POST request URL : *http://127.0.0.1:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CAd62f17e7c7f149ac8095f7574495d988* + +==== Parameters: + +**Url**=http://127.0.0.1:8080/restcomm/dial­alice.xml + +---- +curl ­X POST +http://ACae6e420f425248d6a26948c17a9e2acf:dcd25094354d425c8ab85b6621083d20@192.168.1.151:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CAccccfd3a0c394cc1993803af785abc60 ­-d +"Url=http://192.168.1.151:8080/restcomm/demos/dial­alice.xml" +---- + +=== Redirect Call to a new RCML and connect both call legs +Live Call Modification POST request URL: *http://127.0.0.1:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CAd62f17e7c7f149ac8095f7574495d988* + +==== Parameters + +**Url**=http://127.0.0.1:8080/restcomm/conference.xml + +---- +curl ­X POST +http://ACae6e420f425248d6a26948c17a9e2acf:dcd25094354d425c8ab85b6621083d20@192.168.1.151:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CAccccfd3a0c394cc1993803af785abc60 ­-d +"Url=http://192.168.1.151:8080/restcomm/demos/conference.xml" ­-d +"MoveConnectedCallLeg=true" +---- + +=== Terminate In Progress call +Live Call Modification POST request URL: *http://127.0.0.1:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CAe29bf33b54ba43dc952f0d3eb331567c* + +==== Parameters: +**Status**=completed + +=== Terminate Ringing call +Live Call Modification POST request URL: *http://127.0.0.1:8080/restcomm/2012­04­24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json/CA312824ebd262419dbd4c00b057448d57*   + +==== Parameters: +**Status**=canceled   + +== Modifying Live Calls - Example + +* In order to accomplish this, you need to create a client called alice +* Start a *SIP* phone and register alice +* From the terminal run the following curl command +* Make sure alice is using the port *5061* +* The "**From=**" could be any number of your choice +* The *Url* is the default sample example provided with Restcomm + +Modifying a Live Call + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls.json -d "From=+16175551212" -d "To=sip:alice@127.0.0.1:5061" -d "Url=http://127.0.0.1:8080/restcomm/demos/hello-play.xml" +---- + +You will see an output similar to the one below: + +---- +{ + "sid": "CAfa51b104354440b09213d04752f50271", + "date_created": "2013-11-01T03:41:14.488-06:00", + "date_updated": "2013-11-01T03:41:14.488-06:00", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "to": "alice", + "from": "+16175551212", + "status": "queued", + "start_time": "2013-11-01T03:41:14.488-06:00", + "price": "0.0", + "direction": "outbound-api", + "api_version": "2012-04-24", + "uri": "/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271.json", + "subresource_uris": { + "notifications": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271/Notifications", + "recordings": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271/Recordings" + } +---- + +Notice the "sid": "CAfa51b104354440b09213d04752f50271", +This Call ID is what you must use to interact with the current call. +You can now redirect the current call to another application as shown below +Notice that the Call ID is referenced +The call will now be redirected to the Url specified(hello-world.xml) + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271 -d "Url=http://127.0.0.1:8080/restcomm/demos/hello-world.xml" +---- + +The output showing the same Call ID + +---- + + + CAfa51b104354440b09213d04752f50271 + 2013-11-01T03:41:14.488-06:00 + 2013-11-01T03:41:14.488-06:00 + + ACae6e420f425248d6a26948c17a9e2acf + alice + +16175551212 + + ..... TRUNCATED +---- + +You can still redirect the current call back to the previous application + +---- +curl -X POST http://ACae6e420f425248d6f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271 -d "Url=http://127.0.0.1:8080/restcomm/demos/hello-play.xml" +---- + +The output showing the same Call ID + +---- + + + CAfa51b104354440b09213d04752f50271 + 2013-11-01T03:41:14.488-06:00 + 2013-11-01T03:41:14.488-06:00 + + ACae6e420f425248d6a26948c17a9e2acf + alice + +16175551212 + + ..... TRUNCATED +---- + +You can end the call using the Status=completed command as shown below + +---- +curl -X POST http://ACae6e420f425248d6f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAfa51b104354440b09213d04752f50271 -d "Status=completed" +---- + +The output showing the same Call ID + +---- + + + CAfa51b104354440b09213d04752f50271 + 2013-11-01T03:41:14.488-06:00 + 2013-11-01T03:41:14.488-06:00 + + ACae6e420f425248d6a26948c17a9e2acf + alice + +16175551212 + + ..... TRUNCATED +---- + +Check LiveCallModification test scripts for Hold/Unhold calls at: https://github.com/RestComm/Restcomm-Connect/tree/master/liveCallModification + +You can Mute/unMute an inprogress call as shown bellow. + +.Mute a Participant +==== +curl -X POST http://:@/restcomm/2012-04-24/Accounts//Conferences//Participants/ -d "Mute=true" +==== + +*Sample Mute Response* +---- + + + CA02b649d3ffe24408a1e141be089f347b + CFcc373b0637114f088eae954fa73f0f57 + Wed, 15 Mar 2017 10:10:57 +0000 + Wed, 15 Mar 2017 10:15:33 +0000 + ACae6e420f425248d6a26948c17a9e2acf + true + false + true + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA02b649d3ffe24408a1e141be089f347b + + +---- + +.unMute a Muted Participant +==== +curl -X POST http://:@/restcomm/2012-04-24/Accounts//Conferences//Participants/ -d "Mute=false" +==== + +*Sample unMute Response* +---- + + + CA02b649d3ffe24408a1e141be089f347b + CFcc373b0637114f088eae954fa73f0f57 + Wed, 15 Mar 2017 10:10:57 +0000 + Wed, 15 Mar 2017 10:16:44 +0000 + ACae6e420f425248d6a26948c17a9e2acf + false + false + true + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA02b649d3ffe24408a1e141be089f347b + + +---- + +== List Filter + +**HTTP GET**. The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================================== +|Parameter |Description +|To |Only show calls to this phone number or Client identifier. +|From |Only show calls from this phone number or Client identifier. +|Status |Only show calls currently in this status. May be queued, ringing, in-progress, canceled, completed, failed, busy, or no-answer. +|StartTime |Only show calls that started on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for calls that started at or before midnight on a date, and StartTime=YYYY-MM-DD for calls that started at or after midnight on a date. +|ParentCallSid |Only show calls spawned by the call with this Sid. +|=========================================================================================================================================================================================================================================================================== + +  + +=== Filter using the From parameter. + +The example below will only return Calls made from client Alice + +.... + curl -X GET http://administrator%40company.com:77f8c12cc7166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls?From=alice +.... + +The result will be similar to the one below + +[source,lang:xml,decode:true] +---- + + + + CAc0fb839632cf444f9066876d5de741e0 + 2013-10-18T04:51:47.643-06:00 + 2013-10-18T04:51:49.174-06:00 + + ACae6e420f425248d6a26948c17a9e2acf + 1234 + alice + + completed + 2013-10-18T04:51:47.671-06:00 + 2013-10-18T04:51:49.174-06:00 + 1 + 0.00 + inbound + + 2012-04-24 + + + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAc0fb839632cf444f9066876d5de741e0 + + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAc0fb839632cf444f9066876d5de741e0/Notifications + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CAc0fb839632cf444f9066876d5de741e0/Recordings + + + +---- + +== Paging Information + +*HTTP GET.* The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|PParameter |Description +|Page |The current page number. Zero-indexed, so the first page is 0. +|NumPages |The total number of pages. +|PageSize |How many items are in each page +|Total |The total number of items in the list. +|Start |The position in the overall list of the first item in this page. +|End |The position in the overall list of the last item in this page. +|======================================================================= + +  + +=== Example. + +The command below will return a single item from the list of calls using the PageSize parameter + +.... +curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls?PageSize=1 +.... + +The result of the *PageSize* parameter + +[source,lang:xml,decode:true] +---- + + + + CA4049cf008d6b4277b92ab863fd4ec7c8 + 2013-10-18T04:49:45.942-06:00 + 2013-10-18T04:49:46.272-06:00 + + ACae6e420f425248d6a26948c17a9e2acf + 1235 + bob + + completed + 2013-10-18T04:49:45.994-06:00 + 2013-10-18T04:49:46.272-06:00 + 0 + 0.00 + inbound + + 2012-04-24 + + + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA4049cf008d6b4277b92ab863fd4ec7c8 + + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA4049cf008d6b4277b92ab863fd4ec7c8/Notifications + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA4049cf008d6b4277b92ab863fd4ec7c8/Recordings + + + +---- + +  + +== Additional Paging Information. + +The API returns URIs to the next, previous, first and last pages of the returned list as shown in the table below: + +=== Request Parameters + +[cols=",",options="header",] +|============================================================ +|Parameter |Description +|Uri |The URI of the current page. +|Firstpageuri |The URI for the first page of this list. +|Nextpageuri |The URI for the next page of this list. +|Previouspageuri |The URI for the previous page of this list. +|Lastpageuri |The URI for the last page of this list. +|============================================================ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/clients-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/clients-api.adoc new file mode 100644 index 0000000000..fb954ef0e4 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/clients-api.adoc @@ -0,0 +1,224 @@ += Restcomm API – Clients + +== Clients + +An Client instance resource represents a user agent registered with RestComm. + +=== Client Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Clients/\{ClientSid}* + +* Using SIP User Agents. +When using RestComm to handle SIP user agent you have to create a new Client resource, this resource acts as an account for your user agent and also dictates how calls made by the user agent should be handled. + +* Client without VoiceUrl +Restcomm has a new implied behavior when VoiceUrl is not provided for a Client account. Restcomm will proxy calls from such Clients to the destination Client (only if registered) or to the destination Application DID. + +Only registered Clients are allowed to use the *B2BUA/P2P/Proxy* functionalities of Restcomm. Proxying and P2P calls are only allowed between registered(authenticated) Clients. + +The CDR records generated for calls made by Clients, will have account SID the account that the Client belongs to. + +=== Resource Properties + +[cols=",",options="header",] +|=============================================================================================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this client. +|DateCreated |The date that this client was created. +|DateUpdated |The date that this clientr was last updated. +|FriendlyName |A friendly name for this client. +|AccountSid |The unique id of the Account that owns this phone number. +|ApiVersion |Calls to this phone number will create a new RCML session with this API version. +|Login |The name that is used inside the noun. This is also used by the user agent as the user name used for registration and outbound dialing. +|Password |The password used by the user agent during registration and outbound dialing. +|Status |The client status the possible values are 0 for disabled and 1 for enabled. +|VoiceUrl |The URL RestComm will request when this client makes an outbound call. +|VoiceMethod |The HTTP method RestComm will use when requesting the above Url. Either GET or POST. +|VoiceFallbackUrl |The URL that RestComm will request if execution of VoiceUrl fails for any reason. +|VoiceFallbackMethod |The HTTP method RestComm will use when requesting the VoiceFallbackUrl. Either GET or POST. +|VoiceApplicationSid |If this entry contains an Sid to a voice application then RestComm will ignore these voice URLs and use the voice URLs specified by the voice application. +|Uri |The URI for this Client, relative to https://localhost:port/restcomm. +|=============================================================================================================================================================================== + +=== Supported Operations + +*HTTP GET.* Returns the representation of an Client resource, including the properties above. + +*HTTP POST/PUT.* Modifies a Client resource and returns the representation, including the properties above. Below you will find a list of optional parameters. + +=== Request Parameters + +[cols=",",options="header",] +|=============================================================================================================================================================================== +|Parameter |Description +|FriendlyName |A formatted version of this phone number. +|Password |The password used by the user agent during registration and outbound dialing. +|Status |The client status the possible values are 0 for disabled and 1 for enabled. +|VoiceUrl |The URL RestComm will request when this phone number receives a call. +|VoiceMethod |The HTTP method RestComm will use when requesting the above Url. Either GET or POST. +|VoiceFallbackUrl |The URL that RestComm will request if execution of VoiceUrl fails for any reason. +|VoiceFallbackMethod |The HTTP method RestComm will use when requesting the VoiceFallbackUrl. Either GET or POST. +|VoiceApplicationSid |If this entry contains an Sid to a voice application then RestComm will ignore these voice URLs and use the voice URLs specified by the voice application. +|=============================================================================================================================================================================== + +*HTTP DELETE.* Deletes a Client from the user's Account. + +== Client List Resource + +=== Client List Resource URI. + +*/2012-04-24/Accounts/\{AccountSid}/Clients* + +=== Supported Operations +*HTTP GET.* Returns the list representation of all the Client resources for this Account, including the properties above. +*HTTP POST*. Creates a new Client and returns the representation of the resource, including the properties above. Below you will find a list of required and optional parameters. + +=== Request Parameters + +[cols=",",options="header",] +|=============================================================================================================================================================================== +|Parameter |Description +|FriendlyName |A formatted version of this phone number. +|Login |The name that is used inside the noun. This is also used by the user agent as the user name used for registration and outbound dialing. +|Password |The password used by the user agent during registration and outbound dialing. +|Status |The client status the possible values are 0 for disabled and 1 for enabled. +|VoiceUrl |The URL RestComm will request when this phone number receives a call. +|VoiceMethod |The HTTP method RestComm will use when requesting the above Url. Either GET or POST. +|VoiceFallbackUrl |The URL that RestComm will request if execution of VoiceUrl fails for any reason. +|VoiceFallbackMethod |The HTTP method RestComm will use when requesting the VoiceFallbackUrl. Either GET or POST. +|VoiceApplicationSid |If this entry contains an Sid to a voice application then RestComm will ignore these voice URLs and use the voice URLs specified by the voice application. +|=============================================================================================================================================================================== + +== Create a Client + +The client name will be Alice as shown below + +.... + curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients.json -d "Login=alice" -d "Password=test" +.... + +The output of the command will be similar to the one below + +.... +{ + "sid": "CL4e10e3b56a614414bcc1eeca5d96effe", + "date_created": "2013-10-16T08:51:32.460-06:00", + "date_updated": "2013-10-16T08:51:32.460-06:00", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "api_version": "2012-04-24", + "friendly_name": "alice", + "login": "alice", + "password": "test", + "status": "1", + "voice_method": "POST", + "voice_fallback_method": "POST", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL4e10e3b56a614414bcc1eeca5d96effe.json" +.... + +== Delete a Client + +You must use the Client SID + +.... +curl -X DELETE https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL4e10e3b56a614414bcc1eeca5d96effe +.... + +== Change Client's Password + +You must use the Client SID as shown below: + +.... +curl -X PUT https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL4e10e3b56a614414bcc1eeca5d96effe -d "Password=NewPassword" +.... + +== Get List of available Clients + +The command below shows all Clients created using the default Admin Account + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/ +.... + + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:R3stC0mm@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients +---- + +XML GET Response + +[source,lang:xml,decode:true] +---- + + + + CL3003328d0de04ba68f38de85b732ed56 + Mon, 4 Nov 2013 16:33:39 -0500 + Mon, 4 Nov 2013 16:33:39 -0500 + ACae6e420f425248d6a26948c17a9e2acf + 2012-04-24 + bob + bob + i-1c8468a2 + 1 + POST + POST + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56 + + + CLa2b99142e111427fbb489c3de357f60a + Mon, 4 Nov 2013 12:52:44 -0500 + Mon, 4 Nov 2013 12:52:44 -0500 + ACae6e420f425248d6a26948c17a9e2acf + 2012-04-24 + alice + alice + i-1c8468a2 + 1 + POST + POST + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a + + + +---- + + + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:R3stC0mm@127.0.0.1/restcomm/2012-04-24f425248d6a26948c17a9e2acf/Clients.json +---- + +JSON GET Response + +---- +[ + { + "sid": "CL3003328d0de04ba68f38de85b732ed56", + "date_created": "Mon, 4 Nov 2013 16:33:39 -0500", + "date_updated": "Mon, 4 Nov 2013 16:33:39 -0500", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "api_version": "2012-04-24", + "friendly_name": "bob", + "login": "bob", + "password": "i-1c8468a2", + "status": "1", + "voice_method": "POST", + "voice_fallback_method": "POST", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CL3003328d0de04ba68f38de85b732ed56.json" + }, + { + "sid": "CLa2b99142e111427fbb489c3de357f60a", + "date_created": "Mon, 4 Nov 2013 12:52:44 -0500", + "date_updated": "Mon, 4 Nov 2013 12:52:44 -0500", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "api_version": "2012-04-24", + "friendly_name": "alice", + "login": "alice", + "password": "i-1c8468a2", + "status": "1", + "voice_method": "POST", + "voice_fallback_method": "POST", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Clients/CLa2b99142e111427fbb489c3de357f60a.json" + } +] +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/conferences-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/conferences-api.adoc new file mode 100644 index 0000000000..db8454d7aa --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/conferences-api.adoc @@ -0,0 +1,73 @@ +[[conferenceapi]] += Restcomm API – Conferences + +== Conference + +The represents a single conference originated and terminated from an account. + +=== Conference Resource URI + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid} +.... + +=== Resource Properties + +[cols=",",options="header",] +|====================================================================================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this conference. +|FriendlyName |A user provided string that identifies this conference room. +|Status |A string representing the status of the conference. Possible values are RUNNING_MODERATOR_PRESENT, RUNNING_MODERATOR_ABSENT and COMPLETED. +|DateCreated |The date that this conference was created. +|DateUpdated |The date that this conference was last updated. +|AccountSid |The unique id of the Account that created this conference. +|ApiVersion |Displays the current API version +|Uri |The URI for this account, relative to https://localhost:port/restcomm. +|====================================================================================================================================================================== + +=== Supported Operations +**HTTP GET**. Returns the representation of a Conference resource, including the properties above. + +==== Example: Get Conference by ConferenceSid + +.... +curl -H "Authorization: Basic " https://IP/restcomm/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid} +.... + + +**HTTP POST**. +Not supported + +**HTTP PUT**. +Not supported + +**HTTP DELETE**. +Not supported + +**Conference Subresources**. + represent set/list of in-progress calls in a running conference room. + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants +.... + + +== Conference List Resource URI + +.... +/2012-04-24/Accounts/AccountSid}/Conferences +.... + +=== Supported Operations +**HTTP GET**. +Returns the list representation of all the Conference resources for this Account, including the properties above. + +**HTTP POST**. +Not supported + +**HTTP PUT**. +Not supported + +**HTTP DELETE**. +Not supported diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/email-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/email-api.adoc new file mode 100644 index 0000000000..5b71e190b1 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/email-api.adoc @@ -0,0 +1,89 @@ += Restcomm API – Email + +== Email + +Using the RestComm API, you can send Emails through a simple request. + +=== Email resource URI +*/2012-04-24/Accounts/\{AccountSid}**/Email/Messages*** + +=== Resource Properties + +[cols=",",options="header",] +|====================================================================== +|Property |Description +|DateSent |The date that this Email Message was send. +|AccountSid |The unique id of the Account that sent this Email message. +|From |The Email address that initiated the message. +|To |The Email address of the recipient. +|Body |The text body of the email message. +|Subject |The subject of the email message. +|====================================================================== + +=== Supported Operations + +**HTTP POST.** Sends a new Email  message and returns the representation of the Email message resource, including the properties above. Below you will find a list of required and optional parameters. + +=== Request Parameters + +[cols=",",options="header",] +|========================================================================================================== +|Parameter |Description +|From(Required) |The Email address to use as sender address. +|To(Required) |The destination Email address. +|Body(Required) |The body of the Email message. +|Subject(Required) |The subject of the Email message.(Max. 160 chars.) +|BCC |The Blind Carbon Copy feature (Bcc).  (Hide addresses when sending an Email to various recipients) +|CC |The Carbon Copy (Cc). (The list of CCed recipients is visible to all other recipients of the message.) +|========================================================================================================== + +== Using Email +You need to configure Restcomm to send Email messages. For the necessary configuration please refer to this http://docs.telestax.com/restcomm-sending-email-via-restcomm-email-verb/[post] + +=== Send Email Messages + +From a bash terminal, you can run the command below: + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Email/Messages -d "To=email@hotmail.com" -d "From=email@gmail.com" -d "Body=This is a test from RestComm" -d "Subject=Test Email" +.... + +[[example-post-response---xml-and-json]] +Example POST Response - XML and JSON +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* XML POST Response +---- +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Email/Messages -d "To=email@hotmail.com" -d "From=email@gmail.com" -d "Body=This is a test from RestComm" -d "Subject=Test Email" +---- + + +---- + + + 2016-02-07T23:43:03.910Z + ACae6e420f425248d6a26948c17a9e2acf + email@gmail.com + email@hotmail.com + This is a test from RestComm + Test Email + +---- + +* JSON POST Response + +---- +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Email/Messages.json -d "To=email@hotmail.com" -d "From=email@gmail.com" -d "Body=This is a test from RestComm" -d "Subject=Test Email" +---- + + +---- +{ + "date_sent": "2016-02-07T23:54:41.293Z", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "from": "email@gmail.com", + "to": "email@hotmail.com", + "body": "This is a test from RestComm", + "subject": "Test Email" +} +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/error-reference.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/error-reference.adoc new file mode 100644 index 0000000000..1aeba64378 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/error-reference.adoc @@ -0,0 +1,37 @@ +.Restcomm API Error and Warning Reference +[cols="1,1,2,3", options="header"] +|=== + +|Error Code | Category | Error Summary | Cause/Solution + +|10001|Account| Account not initialized | Make sure account is initialized in the Admin UI +|10002|Account|| +|10003|Account|| +|10004|Account|| + +|11001|Voice|| +|11002|Voice|| +|11003|Voice|| +|11004|Voice|| + +|12001|SMS|| +|12002|SMS|| +|12003|SMS|| +|12004|SMS|| + +|13001|SMPP|There was an error sending SMS to SMPP endpoint|Make sure SMPP is correctly configured in the advanced.conf file +|13002|SMPP|| +|13003|SMPP|| +|13004|SMPP|| + +|14001|Client|| +|14002|Client|| +|14003|Client|| +|14004|Client|| + +|15001|USSD|| +|15002|USSD|| +|15003|USSD|| +|15004|USSD|| + +|=== diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/extensions-multiprovider-configuration.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/extensions-multiprovider-configuration.adoc new file mode 100755 index 0000000000..ca5c164106 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/extensions-multiprovider-configuration.adoc @@ -0,0 +1,259 @@ += Restcomm API – Multiprovider Extension + +[[extensions-multiprovider]] +== Multiprovider Extension + +=== High Level Operation + +The Multiprovider extension allows per account SMS and Voice routing. + +IMPORTANT: The MultiProvider feature is available only to Commercial users of Restcomm Connect. + +IMPORTANT: This REST API is only accessible by the super-admin. + + +=== Multiprovider Extension Resource URI + +*/2012-04-24/ExtensionsConfiguration.json/{MultiProviderExtensionId}* + +=== Resource URI Properties + +[cols=",,",options="header",] +|========================================================================================================================= +|Property |Description|Valid Values +|MultiProviderExtensionId |The unique MultiProvider Extension Id. This value will be different for each installation| Valid Extension Sid. eg.EX77f123cf07624366be8c0a9a2150f045 +|========================================================================================================================= + +=== Supported Operations + +*HTTP GET.* Returns the representation of the MultiProvider Extension resource. + +**HTTP POST/PUT**. Adds or modifies MultiProvider configuration for specific Account and returns the representation. Below you will find a list of supported parameters. + +=== Supported Operation Parameters + +[cols=",,",options="header",] +|========================================================================================================================= +|Parameter |Description|Valid Values +|ExtensionName |The unique MultiProvider Extension name. Currently is fixed to "multi_provider"|"multi_provider" +|Enabled |Enable or disable the extension.|"true"\|"false" +|ConfigurationData |The MultiProvider configuration string.|Json string with correct schema +|AccountSid |The Account this MultiProvider configuration is applied to.|Valid AccountSid +|========================================================================================================================= + +==== ConfigurationData Parameter Json Example Structure +[source,JSON] +---- +{ + "outbound-voice": [ + { + "proxy": [ + { + "uri":"Uri", + "username":"String", + "password":"String", + "match":"Regex String", + "headers":[ + { + "headerName":"String", + "key":"String", + "value":"String" + }, + {...} + ] + }, + {...} + ] + } + ], + "outbound-sms": [ + {"destination_network_id":"Integer"} + ] +} +---- +==== ConfigurationData Parameter Top Level Properties +.Top Level +[cols=",,,",options="header",] +|==================================================================== +|Property |Type|Description | Optional +|`outbound-sms` |Array| Array with single OutboundSms object.| Yes +|`outbound-voice` |Array| Array with single OutboundVoice object.| Yes +|==================================================================== + +== SMS Enablement + +MultiProvider Extension enables Account specific SMS routing by sending `destination_network_id` (1550) TLV to the Telestax SMPP server that is configured. + +NOTE: Configuration wise it is possible to inject other TLVs for other purposes aside from SMS routing but this is currently not enabled. +In the future, injection of other arbitrary TLVs may be enabled. + +=== ConfigurationData Parameter OutboundSms Object Properties +.`outbound-sms` Properties +[cols=",,",options="header",] +|==================================================================== +|Property |Description | Optional +|`destination_network_id` |The destination_network_id TLV | No +|==================================================================== +==== `outbound-sms` Json Example +[source,JSON] +-- +{ + "outbound-sms": [ + {"destination_network_id":"1000"} + ] +} +-- +=== Example SMS Enablement + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acg:77f8c12cc7b8f8423e5c38b035249166@10.0.0.4:8080/restcomm/2012-04-24/ExtensionsConfiguration.json \ +-d "ExtensionName=multi_provider" -d "Enabled=true" \ +-d "AccountSid=ACae6e420f425248d6a26948c17a9e2acf" \ +-d "ConfigurationData={\"outbound-sms\": [{\"destination_network_id\": \"1000\"}]}" +---- + +== Voice Enablement + +MultiProvider Extension voice enablement works three ways + +* Mapping a specific SIP outbound proxy to a specific Account. This applies to PSTN, SIP and Client calls. +- MultiProvider Extension enables Account specific Voice routing to a specific outbound proxy by using the OutboundVoice `uri` property defined in the Account specific ConfigurationData. +- Credentials of the outbound proxy are defined in `username` and `password` properties +- URI properties have to be defined inline in the URI string itself. eg `"uri":"192.168.0.1;uriprop=uri_prop_value1"` +* Appending SIP Message headers with custom header properties and adding custom headers. +- SIP Message headers will be modified when the `headers` property is defined. +- If the header defined in `headerName` is not present in the SIP Message, it is added to the SIP Message. + +* Rewriting SIP Request URI when the initial Request URI matches configured regex pattern. This applies to SIP calls. +** Request URI pattern matching is done when `match` property is defined. +** By default `match` property does not need to be defined. In a configuration where the `match` property is not defined it amounts to configuring the `match` as `"match":".*"` +** Common regex may be used: +*** `"match" : "uri.com"`. Will only match URI `uri.com`. +*** `"match" : "uri[12]\.com"`. Will match URIs `uri1.com`, `uri2.com`. Will not match `uri3.com` +*** `"match" : "^uri.*"`. Will match URIs `uri`, `uri.com`. Will not match `1uri.com` + + +=== ConfigurationData Parameter OutboundVoice Object Properties +.`outbound-voice` Properties +[cols=",,,",options="header",] +|==================================================================== +|Property |Type|Description | Optional +|`proxy` |Array | Array of proxies|No +|==================================================================== + +.`proxy` Array Element Properties +[cols=",,,",options="header",] +|==================================================================== +|Property |Type|Description | Optional +|`uri`|String| Uri of outbound proxy| No +|`username`|String | Username for outbound proxy login|Yes +|`password`|String | Password for outbound proxy login|Yes +|`match` |String | Regex string for sip uri string matching|Yes +|`headers` |Array| Array of headers to be replaced into Sip message|Yes +|==================================================================== + +.`headers` Array Element Properties +[cols=",,,",options="header",] +|==================================================================== +|Property |Type|Description | Optional +|`headerName`|String| Header name in message to append| No +|`key`|String | Key attribute to append to message|No +|`value`|String | Value of attribute to append to message|No +|==================================================================== + +==== `outbound-voice` Json Example +[source,JSON] +---- +{ + "outbound-voice": [ + { + "proxy": [ + { + "uri":"192.168.0.1;uriprop1=uri_prop_value1;uriprop2=uri_prop_value2", + "username":"someuser1", + "password":"somepassword1", + "match":"uri.com" + }, + { + "uri":"192.168.0.1", + "username":"someuser1", + "password":"somepassword1", + "match":"uri[12]\.com", + "headers":[ + { + "headerName":"Request-URI", + "key":"newkey1", + "value":"newvalue1" + }, + { + "headerName":"Request-URI", + "key":"newkey2", + "value":"newvalue2" + }, + { + "headerName":"To", + "key":"newkey3", + "value":"newvalue3" + }, + { + "headerName":"X-CustomHeader", + "key":"newkey4", + "value":"newvalue4" + } + ] + }, + { + "uri":"192.168.0.2", + "username":"someuser2", + "password":"somepassword2", + + "headers":[ + { + "headerName":"Request-URI", + "key":"newkey5", + "value":"newvalue5" + }, + { + "headerName":"Request-URI", + "key":"newkey6", + "value":"newvalue6" + }, + { + "headerName":"To", + "key":"newkey7", + "value":"newvalue7" + }, + { + "headerName":"X-CustomHeader", + "key":"newkey8", + "value":"newvalue8" + } + ] + } + ] + } + ] +} +---- +=== Example Voice Enablement + +---- +curl -X POST http://ACae6e420f425248d6a26948c17a9e2acg:77f8c12cc7b8f8423e5c38b035249166@10.0.0.4:8080/restcomm/2012-04-24/ExtensionsConfiguration.json \ +-d "ExtensionName=multi_provider" -d "Enabled=true" \ +-d "AccountSid=ACae6e420f425248d6a26948c17a9e2acf" \ +-d "ConfigurationData={\"outbound-voice\": [ {\"proxy\": [ \ +{\"uri\":\"192.168.0.1;uriprop1=uri_prop_value1;uriprop2=uri_prop_value2"\", \"username\":\"someuser1.com\", \"password\":\"somepassword1.com\", \"match\":\"uri.com\"}, \ +{\"uri\":\"192.168.0.1\", \"username\":\"someuser1.com\", \"password\":\"somepassword1.com\", \"match\":\"uri[12]\\.com\", \"headers\": [ + {\"headerName\":\"Request-URI\", \"key\":\"newkey1\", \"value\":\"newvalue1\"}, \ + {\"headerName\":\"Request-URI\", \"key\":\"newkey2\", \"value\":\"newvalue2\"}, \ + {\"headerName\":\"To\", \"key\":\"newkey3\", \"value\":\"newvalue3\"}, \ + {\"headerName\":\"X-CustomHeader\", \"key\":\"newkey4\", \"value\":\"newvalue4\"} \ +]} \ +{\"uri\":\"192.168.0.2\", \"username\":\"someuser2.com\", \"password\":\"somepassword2.com\", \"headers\": [ + {\"headerName\":\"Request-URI\", \"key\":\"newkey5\", \"value\":\"newvalue5\"}, \ + {\"headerName\":\"Request-URI\", \"key\":\"newkey6\", \"value\":\"newvalue6\"}, \ + {\"headerName\":\"To\", \"key\":\"newkey\", \"value7\":\"newvalue7\"}, \ + {\"headerName\":\"X-CustomHeader\", \"key\":\"newkey8\", \"value\":\"newvalue8\"} \ +]} \ +] } ] }" +---- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/gateway-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/gateway-api.adoc new file mode 100644 index 0000000000..53200396a5 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/gateway-api.adoc @@ -0,0 +1,63 @@ += Restcomm API – Gateways + +[[gateways]] +== Gateways + +The Gateways subresources let you create sip accounts that Restcomm will use to register itself to the Gateway and receive incoming traffic. This feature is similar to when a SIP phone registers to a Proxy Server and receives inbound calls/messages. In this cases, Restcomm will act as the SIP client initiating the register connection to the Proxy Server. + +=== Gateway List Resource URI +**/2012-04-24/Accounts/\{AccountSid}/Management/Gateways** + +=== Register Restcomm instance to a SIP Gateway.  +You might need to register Restcomm instance to a SIP Gateway and receive incoming traffic from that Gateway. For that you need to use Gateway REST endpoint + +=== Resource Properties + +[cols=",",options="header",] +|==================================================================== +|Property |Description +|FriendlyName |A friendly version of the gateway. +|UserName |The username that will be used to register to this gateway +|Password |The password that will be used to register to this gateway +|Proxy |The proxy address of the gateway +|Register |Boolean flag to register or not the gateway +|TTL |Time to live for the Register +|==================================================================== + +[[supported-operations]] +=== Supported Operations + +**HTTP GET** Returns the representation of a Gateway resource, including the properties above. Resource URI: /2010-04-01/Accounts/\{AccountSid}/Management/Gateways/\{GatewaySid} + +**HTTP POST** Creates a new Gateway resource and returns the representation of the resource, including the properties above. Resource URI: /2010-04-01/Accounts/\{AccountSid}/Management/Gateways + +**HTTP POST/PUT** Update a Gateway resource and returns the representation of the resource, including the properties above. Resource URI: /2010-04-01/Accounts/\{AccountSid}/Management/Gateways/\{GatewaySid} + +**HTTP DELETE** Deletes a Gateway resource. Resource URI: /2010-04-01/Accounts/\{AccountSid}/Management/Gateways/\{GatewaySid} + +[[examples]] +== Examples + +=== Create a new Gateway + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Management/Gateways -d "FriendlyName=mygateway" -d "UserName=username" -d "Password=password" -d "Proxy=my.gateway.com" -d "Register=true" -d "TTL=3600" +.... + +=== Get a list of available Gateways. + +.... +curl -G https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Management/Gateways +.... + +=== Update an existing Gateway. + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Management/Gateways/GW106bc6f34bd24790a435eaeccc1aed72 -d "FriendlyName=MyGatewayNewName" -d "UserName=newUserName" +.... + +=== Delete an existing Gateway. + +.... +curl -X DELETE https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Management/Gateways/GW1cffb069192a45f2b5f5af2e76489550 +.... diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/geolocation-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/geolocation-api.adoc new file mode 100644 index 0000000000..16f8f58e4a --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/geolocation-api.adoc @@ -0,0 +1,1319 @@ += Restcomm API Geolocation + +== Rationale + +The goal of this document is describing and offer an API that Web +Developers can understand without the need of any knowledge about the +underlying Telecom infrastructure and jargon and thus make it as easy as +it gets to include Geolocation as a value-added feature in their +applications. + +The API aims to cater either IP Geolocation (from Restcomm SDKs) or +cellular telephony Geolocation (from Mobile Network Operators core and +radio access networks, either by SS7 MAP or LTE Diameter operations) in +terms of API. + + +The use cases this API aims covering are: + +1. Notify Restcomm the current location of client X or certain +MSISDN/IMSI (e.g. iWatch cardio activity alarm 2015 TADHack Chicago winner-, +E911, friend/family finder, etc.). + +2. Notify Restcomm if client X or certain MSISDN or IMSI enters or exits a +geofence. Use cases like mobile advertising use cases apply to this type of Geolocation service. + +3. Notify Restcomm if client X is within N meters from client Y. Many use cases apply to this type of Geolocation service, namely: + +* Parental control: Notify a parent when their child/children are further than X metres away. + +* Hanging out: Notify friends when they are within X Kms. + +* Business matching: at a conference, notify attendees of other attendees within range who also have related interest based on LinkedIn profile. + +* Court restraining order: when someone is legally not allowed to be writhing certain range of another individual. + +Other use cases will be covered in future iterations of the API based on +community and customer feedback. + + +== Geolocation + + +A *Geolocation* resource represents an outbound Geolocation +service. + +=== Geolocation Resource URI + +Geolocation Resource **URI** distinct in three modes described further +below: + + +*/ApiVersion/Accounts/\{AccountSid}/Geolocation/\{GeolocationSid}* + + +This URI refers to requests that would only allow HTTP GET method to +retrieve previously gathered Geolocation information, regardless of +whether it was an Immediate or Notification Geolocation request. (See +further below for description of those terms). + + +=== Geolocation Resource properties + + + +[width="100%",cols="50%,50%",] +|======================================================================= +|PROPERTY |DESCRIPTION + +|Sid |A string that uniquely identifies this Geolocation service. + +|DateCreated |The date that this Geolocation service was created. + +|DateUpdated |The date that this Geolocation service was last updated. + +|DateExecuted |The date that this Geolocation service was sent. + +|AccountSid |A string that uniquely identifies the account that created +this Geolocation service. + +|Source |A string that uniquely identifies the Geolocation service +client, phone number or device that initiated the Geolocation service. + +|DeviceIdentifier |A string that uniquely identifies the device target +(e.g. phone number, IoT device, ...) of this Geolocation service. + +|GeolocationType: a| +The type of location measurement requested, namely: + +**_Immediate_**: after a successful geolocation attempt has been +delivered with its associated timestamp, the location information and +timestamp are referred to as the current location at that point in +time. + +**_Notification_**: location request where the response/s is/are +required after a specific event has occurred. Event may or may not occur +immediately. In addition, event may occur many times. Examples of these +events: when a device is entering or leaving or being in a pre-defined +geographical area (geofencing); periodic location; when a device becomes +available; when a sensor/beacon detects a threshold surpassed, etc. + +|ResponseStatus a| +A string that uniquely identifies the current state of this Geolocation +service. Possible values are: + +**_queued_**: whenever the location request is buffered due to abnormal +causes (e.g. congestion at the GMLC); + +**_sent_**: when the location request has already been sent but no +response has arrived yet; + +**_processing_**: when the location response has been received but being +under computational process for delivery to the requesting location +client. + +**_successful_**: when the location response has been received and +processed with complete fulfilment of quality of geolocation +information. + +**_partially-successful_**: when the location response has been received +and processed, but not fulfilled the whole set of geolocation +information or desired accuracy, e.g.: geographic coordinates were not +possible to retrieve, but at least other location information such as +Cell/Service and Location/Service Area identifiers were obtained; location information +was retrieved, but the age of location estimate denotes it may be +outdated; location information was retrieved, but informed that +precision is not reliable due to high error margin. + +**_last-known_**: when location information could not be retrieved from +the network but there is a previous persisted location information for +the targeted DeviceIdentifier of this Geolocation service. + +**_failed_**: when location information could not be retrieved from the +network and there is no previous location information persisted for the +targeted DeviceIdentifier of this Geolocation service, or when an +attempt to update this Geolocation service was malformed or not API +compliant. In the latter situation, the record persists, but previous +geolocation information is erased (expecting a correct geolocation +update). + +**_unauthorized_**: when the location request is or has become +disallowed from the network, the location client requesting this service +is not authorized for such operation or the target device is marked for +not authorizing this kind of location requests. A record is persisted +for security and analytics purposes. + +**_rejected_**: when the location request does not meet the API's +requirements for mandatory parameters (or some of them are missing), or +prohibited parameters are included for a certain type of Geolocation. No +records are persisted in this eventuality. + +|GeolocationData a| +An array that uniquely identifies the location information that might be +obtained by this Geolocation service. The fields of this array are +described next: + +**_CellId_**: an identifier assigned to a specific radio coverage area +known as cell or service area; + +**_LocationAreaCode_**: an identifier assigned to a group of cells or service area; + +**_MobileCountryCode_**: code number of the country of the mobile +network as specified by E.212. + +**_MobileNetworkCode_**: code number of the mobile network in a specific +country as specified by E.212. + +**_NetworkEntityAddress_**: code number of the mobile network entity +addressed for this Geolocation service. + +**_LocationAge_**: indication of how long ago the network location +identifiers were recorded (informed in minutes); + +**_DeviceLatitude_**: an estimate of the location of the phone number, +device/beacon or closest WiFi Access Point in the geographic +coordinate that specifies the north-south position of a point on the +Earth's surface. + +WGS84 is used, whose formats for Latitude are described next: + +Latitude valid formats include: + + N43°38'19.39" + +   43°38'19.39"N + +   43 38 19.39 + +   43.63871944444445 + +If expressed in decimal form, northern latitudes are positive, southern +latitudes are negative. The following longitude variants are also allowed: + +   N43 38 19.39 + +   43 38 19.39N + +**_DeviceLongitude_**: an estimate of the location of the phone number, +device/beacon or closest WiFi Access Point in the geographic +coordinate that specifies the north-south position of a point on the +Earth's surface. + +WGS84 is used, whose formats for Longitude are described next: + +Longitude valid formats include: + +   W116°14'28.86" + +   116°14'28.86"W + +   -116 14 28.86 + +   -116.2413513485235 + +If expressed in decimal form, eastern longitudes are positive, western +longitudes are negative. The following longitude variants are also allowed: + +   W116 14 28.86 + +   116 14 28.86W + +**_Accuracy_**: quality of location information or estimated precision +for this Geolocation service in meters. This information will be present +depending on available location procedures at the radio access network. + +**_PhysicalAddress_**: MAC address of the device/beacon or closest +closest WiFi Access Point. + +**_InternetAddress_**: IP address of the phone number, device/beacon or +closest closest WiFi Access Point. + +*__FormattedAddress__:* refers to the civic location of the phone +number, device/beacon or closest WiFi Access Point, expressed as civic +data (e.g. floor, street number, city.) It shall be represented in a +well-defined universal format, compliant with Google Geolocation API +"formatted_address" json/xml field. + +**_LocationTimestamp_**: indication of when the geolocation information +was gathered (informed as a time stamp); + +*_EventGeofenceLatitude:_* refers to the geographic coordinates +latitude of a specific location. Used to notify when a device is within +a certain distance (in metres) from that specific location. Same format used as for DeviceLatitude parameter. + +*_EventGeofenceLongitude:_* refers to the geographic coordinates +longitude of a specific location. Used to notify when a device is within +a certain distance (in metres) from that specific location. Same format used as for DeviceLongitude parameter. + +*_Radius:_* distance in meters from the Geofence geographic coordinates. + +|GeolocationPositioningType a| +Indication of the positioning method used to determine the Geolocation +data, either successfully or unsuccessfully. Possible values are: + +**_last-known_**: last known device location position stored at a +database (Location Server, HLR, etc.) from which the information is +retrieved. + +**_Network_**: location information retrieved from improved measurement +techniques executed at the radio access network, either for IP or +cellular networks (e.g. timing advanced, multilateration, etc.). + +**_GPS_**: location information assisted by the Global Navigation +Satellite System (GNSS), which includes GPS (as well as GLONASS and +Galileo). + +|LastGeolocationResponse |Indication whether GeolocationData +values provided are the last to be gathered in this Geolocation +request (true/yes) or further are expected to be sent asynchronously (false/no) to the StatusCallback URL. + +|Cause |Reason of an unsuccessful or rejected Geolocation request. + +|ApiVersion |The API version RestComm used to handle the Geolocation +service. + +|Uri |The URI for this account, relative to +http://localhost:port/restcomm. +|======================================================================= + + +=== Supported Operations + +**HTTP GET**. Returns the list representation of all the service +resources for this account, including the properties above. + + +== Immediate Geolocation + +==== Immediate Geolocation URI + +*/ApiVersion/Accounts/\{AccountSid}/Geolocation/Immediate/\{GeolocationSid}* + + +This URI mode refers to requests for retrieval of current or last known +Geolocation information (an associated timestamp will be included in the +response). Geolocation information might include very accurate location +data in terms of geographic coordinates, or just location identifiers +like the radio base station transceiver identity of a cellular network +that is currently providing service to the target device. Accuracy will +depend on the available radio access location procedures, either within +a Mobile Network Operator for mobile handsets location within a cellular +Radio Access Network, or a WLAN/WiFi covered area for IP location. + + +=== Supported Operations + + +**HTTP GET**. Returns the list representation of all the service +resources for this account, including the properties above. + + +**HTTP POST**. Sends a new location request and returns the +representation of the Location request resource, including the +properties above. + + +**HTTP PUT**. Updates an Immediate Geolocation request and returns the +representation of the Geolocation request resource, including the +properties above. + +**HTTP DELETE**. Stops an Immediate Geolocation request previously +created or updated + +=== Immediate Geolocation list of required parameters + + +[width="100%",cols="50%,50%",] +|======================================================================= +|PARAMETER |DESCRIPTION + + +|DeviceIdentifier |The target E.164 (MSISDN) or E.212 (IMSI) phone number or device identity of +this Geolocation service. + + +|StatusCallback |A URL that RestComm will use when the Geolocation +service reaches a state that demands notifying the requesting +application. Note: Typically, if the Geolocation request is using Low +Accuracy, the Geolocation information can be retrieved quickly, thus the +result may be returned synchronously. For more precise accuracy, it will +take longer to gather the Geolocation information, as such this URL will +be called back (potentially multiple times) as the Geolocation +information is gathered. +|======================================================================= + + +=== Immediate Geolocation examples + +===== Example 1.- Geolocation of a specific IP device associated to a User; Partial and Successful answers, whole Status Callback cycle example + + +See below a curl example for a Geolocation request originated from a +mobile (iOS or Android) location client. This Geolocation service +assumes WiFi connection only, thus the location information is obtained +from an Access Point (AP) management system, typically placed in indoors +surroundings like shopping centers, theaters, domes, etc. + + +In the first instance, the Location Server cannot determine a precise +location information, responding back with the last known location. +Later, best available accuracy is processed and informed back to the +corresponding Status Callback URL. + + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate -d "DeviceIdentifier=client:david" -d "StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + + +See the corresponding response below for a partially-successful +positioning procedure: + + +.... + +   +     GLfa51b104354440b09213d04752f50271 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:12 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     client:david +     immediate +     partially-successful +     +             33.786442 +             -84.38103 +             00-41-76-C0-00-D1 +             65.17.24.177 +             187 14th St NE Atlanta, GA 30309-2674, +             USA +             Mon, 25 Jan 2016 16:36:12 -0500 +     +     last-known +     false +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50271 +   + +.... + + +Next, see the corresponding status callback after a network measurement +updated the previously stored last known location data (still a +partially-successful positioning procedure though, desired accuracy is +not accomplished yet): + + +.... + +   +     GLfa51b104354440b09213d04752f50271 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:25 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     client:david +     immediate +     partially-successful +     +     33.770002 +          -84.5200998 +          150 +          00-41-76-C0-00-D1 +          65.17.21.37 +          37 5th St NE Atlanta, GA 30310-2179, USA +          Mon, 25 Jan 2016 16:36:25 -0500 +     +     Network +     false +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50271 +   + +.... + + +Finally, see the corresponding response below for the successful +positioning procedure informed in a posterior status callback when high +accuracy is accomplished through GPS assistance: + +.... + +   +     GLfa51b104354440b09213d04752f50271 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:38:24 -0500 +    Mon, 25 Jan 2016 16:36:10 -0500 +    ACae6e420f425248d6a26948c17a9e2acf +    client:david +    immediate +    partially-successful +    +          33.870042 +          -84.5190103 +          5 +          00-41-76-C0-00-D1 +          65.17.21.37 +          34 5th St NE Atlanta, GA 30310-2178, USA +          Mon, 25 Jan 2016 16:38:24 -0500 +     +    GPS +     true +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50271 +  + +.... + + +==== Example 2.- Geolocation of a specific Mobile device associated to a phone number; response including geographic coordinates + + +See below a curl example for a Geolocation request originated initiated +by E.164 phone number 59899549878 requesting location information of +E.164 phone number 59897018375. + + +This case assumes that the Geolocation information is retrieved +successfully from a cellular network with capabilities for obtaining +geographic coordinates (multilateration with at least three base +stations) as well as core and radio access network identifiers: + + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate -d "DeviceIdentifier=59897018375" -d "StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below: + +.... + +   +     GLfa51b104354440b09213d04752f50272 +     Mon, 25 Jan 2016 16:36:10 -0300 +     Mon, 25 Jan 2016 16:37:21 -0300 +     Mon, 25 Jan 2016 16:36:10 -0300 +     ACae6e420f425248d6a26948c17a9e2acf +     59897018375 +     immediate +     successful +     +          90183B +          751 +          748 +          01 +          59800023041 +          0 +          -34.541079 +          -56.1421274 +          50 +          Mon, 25 Jan 2016 16:37:21 -0300 +     +     Network +     true +    2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50272 +   + +.... + + +==== Example 3.- Geolocation of a specific Mobile Device associated to a phone number; no geographic coordinates included in response + +See below a curl example for a Geolocation request originated from an +application called eTop requesting location information of E.164 phone +number 59897018375. As you can see, the request demands a JSON response. + +This case assumes that the Geolocation information is retrieved from a +cellular network, but in contrast with example 1, with no capabilities +for obtaining geographic coordinates but at least core and radio access +network identifiers are available (typical of 2G cellular networks): + + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate.json -d "DeviceIdentifier=39897018375" -d "StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below: + +.... +{ + "sid": "GLfa51b104354440b09213d04752f50273", + "date_created": "Mon, 25 Jan 2016 16:36:10 +0200", + "date_updated": "Mon, 25 Jan 2016 16:36:11 +0200", + "date_executed": "Mon, 25 Jan 2016 16:36:10 +0200", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "device_identifier": "39897018375", + "geolocation_type": "Immediate", + "response_status": "partially-successful", + "geolocation_data": { + "CellId": "191", + "LocationAreaCode": "901", + "MobileCountryCode": "222", + "MobileNetworkCode": "48", + "NetworkEntityAddress": "3980000101", + "LocationAge": "0", + "location_timestamp": "Mon, 25 Jan 2016 16:36:11 +0200" + }, + "geolocation_positioning_type": "Network", + "last_geolocation_response": "true", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50273.json" +} +.... + +==== Example 4.- Geolocation of a specific IP device associated to a user: Failed execution response + +See below a curl example for a Geolocation request originated from a +mobile (iOS or Android) location client, exactly like the latest +example, but on this occasion with a failed result (e.g. no geographic +coordinates or civic address could be obtained from the AP management +system): + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate -d "DeviceIdentifier=sip:david@65.17.24.177" -d "StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below: + +.... + +   +    GLfa51b104354440b09213d04752f50274 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:37 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     sip:david@65.17.24.177 +     immediate +     failed +     +     Timeout, no response from network +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50274 +   + +.... + +Note: records are persisted when ResponseStatus equals failed, thus +they could be updated by a further operation, a POST or PUT request, or +retrieved by a GET request. + +==== Example 5.- Geolocation update of a previously failed request + +See below a curl example for updating the previous Geolocation request example. In this case, the last known location is set instead of the empty location data response obtained previously due to a network failure. + +.... +curl -X PUT -H "application/json" http://ACae6e420f425248d6a26948c17a9e2acf:f8bc1274677b173d1a1cf3b9924eaa7e@192.168.118.134:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50274 -d "DeviceLatitude=43.257134" -d "DeviceLongitude=-3.496932" -d "LocationTimestamp=2016-01-17T20:32:28.488-04:00" -d "PhysicalAddress=D8-97-BA-19-02-D8" -d "InternetAddress=2001:0:9d38:6ab8:30a5:1c9d:58c6:5898" -d "LastGeolocationResponse=false" -d "GeolocationPositioningType=last-known" +.... + +See the corresponding response below: + +.... + + + GLfa51b104354440b09213d04752f50274 + Mon, 25 Jan 2016 16:36:10 -0500 + Mon, 25 Jan 2016 20:40:10 -0500 + Mon, 25 Jan 2016 16:36:10 -0500 + ACae6e420f425248d6a26948c17a9e2acf + sip:david@65.17.24.177 + Immediate + last-known + + 35.669860 + -81.22147 + 2001:0:9d38:6ab8:30a5:1c9d:58c6:5898 + D8-97-BA-19-02-D8 + Sun, 17 Jan 2016 21:32:28 -0500 + + last-known + false + 2012-04-24 + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50274 + + +.... + +==== Example 6.- Getting information of a specific previously satisfactory created Geolocation Request + +See below a curl example of retrieving the information of the Geolocation service request from the previous example: + +.... +curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50274.json +.... + +See the corresponding response below (the XML response would be exactly as shown previously for the POST request): + +.... +{ + "sid": "GLfa51b104354440b09213d04752f50274", + "date_created": "Mon, 25 Jan 2016 16:36:10 -0500", + "date_updated": "Mon, 25 Jan 2016 20:40:10 -0500", + "date_executed": "Mon, 25 Jan 2016 16:36:10 -0500", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "device_identifier": "sip:david@65.17.24.177", + "geolocation_type": "Immediate", + "response_status": "last-known", + "geolocation_data": { + "device_latitude": "35.669860", + "device_longitude": "-81.22147", + "internet_address": "2001:0:9d38:6ab8:30a5:1c9d:58c6:5898", + "physical_address": "D8-97-BA-19-02-D8", + "location_timestamp": "Sun, 17 Jan 2016 21:32:28 -0500" + }, + "geolocation_positioning_type": "last-known", + "last_geolocation_response": "false", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate/GLfa51b104354440b09213d04752f50274.json" +} +.... + +==== Example 7.- Rejected Immediate Geolocation request + +See below a curl example for a Geolocation request originated from a RestComm Location Client, but on this occasion with a "rejected" result as a mandatory parameter is missing: + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Immediate -d "DeviceIdentifier=4498750163" +.... + +This request gets an "HTTP/1.1 400 Bad Request" response with the following text: + +.... +StatusCallback value can not be null +.... + +No records are persisted for "HTTP/1.1 400 Bad Request" responses, +thus they cannot be updated by either a further POST or PUT request, or +retrieved through a GET request. + + +== Notification Geolocation + +==== Notification Location URI + +*/ApiVersion/Accounts/\{AccountSid}/Geolocation/Notification/\{GeolocationSid}* + + +This URI mode refers to requests for retrieval of current or future +event related GeoLocation information. The response may occur some time +after the request was sent. Examples include geofencing, device +availability/presence alerts, sensors/beacons, alarms, etc. Relative +GeoLocation data (distance to a specific spot), time intervals and +amount of occurrences and other kinds of event associated operational +information can be included from this mode request. + +=== Supported Operations + +**HTTP GET**. Returns the list representation of all the service +resources for this account, including the properties above. + +**HTTP POST**. Sends a new Geolocation Notification request and returns +the representation of the Geolocation request resource, including the +properties above. + +**HTTP PUT**. Updates a GeoLocation Notification request and returns the +representation of the Geolocation request resource, including the +properties above. + +**HTTP DELETE**. Stops a Geolocation Notification request previously +created or updated + + +=== Notification Geolocation list of required parameters + +Parameters below apply for Notification type of Geolocation. +Notification applies to a location request where the response/s and +GeoLocation Data is/are required after a specific event has occurred. +Event may or may not occur immediately. In addition, event may occur +many times. Examples of these events: when a device is entering or +leaving or being in a pre-defined geographical area (geofencing); +periodic GeoLocation; when a device becomes available; when a +sensor/beacon detects a threshold surpassed, etc. + + +[width="100%",cols="50%,50%",] +|======================================================================= +|PARAMETER |DESCRIPTION + + +|DeviceIdentifier |The target E.164 phone number or device identity of +this Geolocation service. + +|EventGeofenceLatitude a| +This parameter refers to the geographic coordinates latitude of a +specific location. Used to notify when a device is within a certain +distance (in metres) from that specific location. + +WGS84 is used, whose formats for Latitude is described next: + +Latitude valid formats include: + +   N43°38'19.39" + +   43°38'19.39"N + +   43 38 19.39 + +   43.63871944444445 + +If expressed in decimal form, northern latitudes are positive, southern +latitudes are negative. The following latitude variants are also allowed: + +   N43 38 19.39 + +   43 38 19.39N + + +|EventGeofenceLongitude a| +Same as previous, but for geographic coordinates longitude. + +WGS84 is used, whose formats for Longitude is described next: + +Longitude valid formats include: + +   W116°14'28.86" + +   116°14'28.86"W + +   -116 14 28.86 + +   -116.2413513485235 + +If expressed in decimal form, eastern longitudes are positive, western +longitudes are negative.The following longitude variants are also allowed: + +   W116 14 28.86 + +   116 14 28.86W + +|GeofenceRange |Distance in meters from the specific location denoted by +EventGeofenceLatitude and EventGeofenceLongitude geographic +coordinates, that would require a Geolocation procedure (e.g. as an +alert that certain device is within a specific location area framed with +beacons, sensors, etc.). + +|GeofenceEvent a| +Indication if this Notification Geolocation service is intended to +inform about a target device entering or leaving a certain location area +(implicitly specified by EventGeofenceLatitude, +EventGeofenceLongitude and GeofenceRange parameters). Allowed values +are: + +- in: reports when the target device has been detected within +the specified location area. + +- out: reports when the target device has been detected leaving +the specified location area. + +- in-out: reports when the target device has been detected +either entering or leaving the specified location area. + +|StatusCallback |A URL that RestComm will use when the Geolocation +service reaches a state that demands notifying the requesting +application. +|======================================================================= + + + +=== Notification Geolocation examples + + +==== Example 1: Geolocation of a specific IP device when it enters a 1km +range of a specific Geolocation - Partial and Successful answers, whole +Status Callback cycle example + +See below a curl example for a Geolocation request of a device under +WiFi access whenever its distance to a specific geographic position is +1000 metres (e.g.: the position of a beacon sensing tracking anklets of +an offender). The example response provides location information every +time the target device enters such location area. + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification-d "DeviceIdentifier=56790122158" -d +"EventGeofenceLatitude=-33.426280" -d +"EventGeofenceLongitude=-70.566560" -d "GeofenceRange=1000" -d +"GeofenceEvent=in" -d "StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below for a partially-successful +positioning procedure, where only last known stored location information +is obtained: + + +.... + +   +     GLfa51b104354440b09213d04752f50275 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:15 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     56790122158 +     notification +     partially-successful +     +          Mon, 25 Jan 2016 16:36:15 -0500 +          -34.800182 +          -71.579001 +          178956.60 +          200.1.122.4 +          00-50-56-C0-00-08 +     +     last-known +     false +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50275 +   + +.... + + +Next, see the corresponding status callback after a network measurement +updated the previously stored last known location data (still a +partially-successful positioning procedure though, desired accuracy is +not accomplished yet): + + +.... + +   +     GLfa51b104354440b09213d04752f50275 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:44 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     56790122158 +     notification +     partially-successful +     +          Mon, 25 Jan 2016 16:36:44 -0500 +          -33.428423 +          -70.5678026 +          220 +          264.73 +          00-50-56-C0-00-08 +          201.2.108.42 +     +     Network +    false +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50275 +   + +.... + +Finally, see the corresponding response below for the successful +positioning procedure informed in a posterior status callback when high +accuracy is accomplished through GPS assistance: + +.... + +   +     GLfa51b104354440b09213d04752f50275 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:37:04 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     56790122158 +     notification +     partially-successful +     +          Mon, 25 Jan 2016 16:37:04 -0500 +          -33.426391 +          -70.566399 +          10 +          19.38 +          00-50-56-C0-00-08 +          201.2.108.42 +     +     GPS +     true +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50275 +   + +.... + + +==== Example 2.- Geolocation of a specific IP device when it enters a 1km range of a specific Geolocation: Unauthorized Answer + + +See below a curl the exact same example of the latter Geolocation +request but for an unauthorized device at the AP management system: + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification -d "DeviceIdentifier=56790122158" -d +"EventGeofenceLatitude=-33.426280" -d +"EventGeofenceLongitude=-70.566560" -d "GeofenceRange=1000" -d +"GeofenceEvent=in" -d +"StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below: + +.... + +   +     GLfa51b104354440b09213d04752f50276 +     Mon, 25 Jan 2016 16:36:10 -0500 +     Mon, 25 Jan 2016 16:36:12 -0500 +     Mon, 25 Jan 2016 16:36:10 -0500 +     ACae6e420f425248d6a26948c17a9e2acf +     56790122158 +     notification +     unauthorized +     +     Target device not allowed by the network +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50276 +   + +.... + + +Note: records are persisted when ResponseStatus equals "unauthorized". + + +==== Example 3.- Geolocation of a specific IP device when it enters a 1km range of a specific Geolocation: Rejected Answer + +See below a curl of the exact same example of the latter Geolocation +request but inappropriately as GeofenceEvent parameter is missing: + + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification -d "DeviceIdentifier=56790122158" -d +"EventGeofenceLatitude=-33.426280" -d +"EventGeofenceLongitude=-70.566560" -d "GeofenceRange=1000" -d +"GeofenceEvent=both" -d +"StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +This request gets an HTTP/1.1 400 Bad Request response with the following text: + +.... +StatusCallback value can not be null +.... + +No records are persisted for HTTP/1.1 400 Bad Request responses, +thus they cannot be updated by either a further POST or PUT request, or +retrieved through a GET request. + +==== Example 4.- Geolocation of a specific IP device when it enters a 200 meters range of a specific Geolocation: Success Answer + + +See below a curl example for a Geolocation request of a mobile phone +under cellular radio access is entering or leaving a location area +specified by a 200 metres distance to the geographic location of a +specific business shop (e.g.: for mobile advertising). The example +response additionally provides location information in terms of the +radio access network identifiers which triggered the positioning method. +The accuracy of location information is gathered as Average (100m to +300m of error margin), which could prevent further actions as only +High accuracy could be set for them (e.g. mobile advertising +containing a special offer): + + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification -d "DeviceIdentifier=SB7089A" -d +"EventGeofenceLatitude=35.526280" -d "EventGeofenceLongitude=139.566560" +-d "GeofenceRange=200" -d "GeofenceEvent=in-out" -d +"StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + + +See the corresponding response below: + +.... + +   +     GLfa51b104354440b09213d04752f50278 +     Mon, 25 Jan 2016 16:36:10 +0900 +     Mon, 25 Jan 2016 16:41:10 +0900 +     Mon, 25 Jan 2016 16:36:10 +0900 +     ACae6e420f425248d6a26948c17a9e2acf +     SB7089A +     notification +     successful +     +          47501A +          239 +          441 +          98 +          810002304 +          0 +          35.526375 +          139.566802 +          50 +          24 +          Mon, 25 Jan 2016 16:41:10 +0900 +     +     Network +     true +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50278 +   + +.... + + +==== Example 5.- Geolocation of a specific IP device when it enters a 300m range of a specific Geolocation with High Accuracy: Success Answer + + +See below a curl example for a Geolocation request originated from +location client within a mobile (iOS or Android) application, that +expects to be informed about entering a specific location area, within +300 metres from a specific geographic spot. The service could serve +several purposes (emergency services, friends and family finder, etc.). + + +In this case, the location information is assumed to be retrieved in JSON format from +an LTE-Advanced cellular network, where all location data parameters can +be obtained, including parameters such as civic address +("FormattedAddress" parameter): + +.... +curl -X POST -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification.json +-d "Source=59897018375" -d "DeviceIdentifier=59897018375" -d +"EventGeofenceLatitude=-34.541078" -d +"EventGeofenceLongitude=-56.061600" -d "GeofenceRange=300" -d +"GeofenceEvent=in" -d "DesiredAccuracy=High" -d +"StatusCallback=http://192.16.1.19:8080/ACae6e420f425248d6a26948c17a9e2acf" +.... + +See the corresponding response below: + +.... +{ + "sid": "GLfa51b104354440b09213d04752f50279", + "date_created": "Mon, 25 Jan 2016 16:36:10 -0300", + "date_updated": "Mon, 25 Jan 2016 16:37:18 -0300", + "date_executed": "Mon, 25 Jan 2016 16:36:10 -0300", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "device_identifier": "59897018375", + "geolocation_type": "Notification", + "response_status": "successful", + "geolocation_data": { + "cell_id": "908", + "location_area_code": "751", + "mobile_country_code": 748, + "mobile_network_code": "1", + "network_entity_address": 59800023041, + "location_age": 0, + "device_latitude": "-34.542029", + "device_longitude": "56.058181", + "accuracy": 5, + "internet_address": "167.57.122.14", + "physical_address": "00-50-56-C0-00-08", + "formatted_address": "Avenida Italia 2552, 11500, Montevideo, Uruguay", + "location_timestamp": "Mon, 25 Jan 2016 16:37:17 -0300", + "event_geofence_latitude": "-34.551098", + "event_geofence_longitude": "-70.601700", + "radius": 115.24 + }, + "geolocation_positioning_type": "GPS", + "last_geolocation_response": "true", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50279.json" +} +.... + +==== Example 6.- Update previous GeoLocation request for a specific IP device when it exits a 300m range of a specific Geolocation: Success Answer + +See below a curl example for updating the previous Geolocation +request example, where geographic coordinates of the geofence location are +modified, as well as the event type (leaving the location area instead +of entering it as set in the previous example). + +.... +curl -X PUT -H "application/json" +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50280 -d "EventGeofenceLatitude=-34.553098" -d "EventGeofenceLongitude=56.050811" -d "GeofenceEvent=out" +.... + + +See the corresponding response below: + + +.... + +   +     GLfa51b104354440b09213d04752f50280 +     Mon, 25 Jan 2016 16:38:10 -0300 +     Mon, 25 Jan 2016 16:39:18 -0300 +     Mon, 25 Jan 2016 16:36:10 -0300 +     ACae6e420f425248d6a26948c17a9e2acf +     59897018375 +     notification +     partially-successful +     +          90182A +          751 +          748 +          01 +          59800023041 +          0 +          -34.560071 +          56.057710 +          180 +          115 +          167.57.122.14 +          00-50-56-C0-00-08 +          Avenida Italia 2552, 11500, Montevideo, Uruguay +          Mon, 25 Jan 2016 16:37:18 -0300 +     +     Network +     true +     2012-04-24 +     /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50280 +   + +.... + + + +==== Example 7.- Retrieve information of a specific previously satisfactory created Geolocation Request + +See below a curl example of retrieving the information of the Geolocation service request from previous example: + +.... +curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50280.json +.... + +See the corresponding JSON response below (the XML response would be exactly as shown previously for the POST request): + +.... +{ + "sid": "GLfa51b104354440b09213d04752f50280", + "date_created": "Mon, 25 Jan 2016 16:38:10 -0300", + "date_updated": "Mon, 25 Jan 2016 16:39:18 -0300", + "date_executed": "Mon, 25 Jan 2016 16:36:10 -0300", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "device_identifier": "59897018375", + "geolocation_type": "Notification", + "response_status": "partially-successful", + "geolocation_data": { + "cell_id": "90182A", + "location_area_code": "751", + "mobile_country_code": 748, + "mobile_network_code": "01", + "network_entity_address": 59800023041, + "location_age": 0, + "device_latitude": "-34.560071", + "device_longitude": "56.057710", + "accuracy": 180, + "internet_address": "167.57.122.14", + "physical_address": "00-50-56-C0-00-08", + "formatted_address": "Avenida Italia 2552, 11500, Montevideo, Uruguay", + "location_timestamp": "Mon, 25 Jan 2016 16:37:18 -0300", + "event_geofence_latitude": "-34.551098", + "event_geofence_longitude": "-70.601700", + "radius": 115 + }, + "geolocation_positioning_type": "last-known", + "last_geolocation_response": "true", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50280.json" +} +.... + + +==== Example 8.- Stop Notifications of a specific previously created Geolocation Request + +See below a curl example for stopping notifications of a previously +created Geolocation request. + +.... +curl -X DELETE +http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Geolocation/Notification/GLfa51b104354440b09213d04752f50280 +.... + + + + +== IP Geolocation Sequence Diagram + + +IP Immediate Geolocation Sequence Diagram of RestComm with Olympus +Clients and RestComm Mobile/Web SDKs + + + +image:images/IPGeolocationSequenceDiagram.gif[image,width=633,height=230] + + + +For the Notification case the diagram is similar, except that the device +can store the information and notify RestComm when it approaches a +certain location area. + +== Cellular Geolocation Sequence Diagrams + + +Next diagram shows the interaction between RestComm and GMLC within a GSM network, from where location services are reduced to retrieving Global Cell Identity, Age of Location information and network node address at which the target mobile subscriber is +currently currently attached. + +image:images/RestComm_GSM_Immediate_Geolocation.png[image,width=633,height=230] + + +Next diagram exhibits a Notification type of Geolocation signal flow in 3G cellular networks. An Immediate type of Geolocation signal flow in the same environment would be identical, except for the event detection and its derived signals. Besides, for the sake of simplicity, it only shows a single event detection. + +image:images/RestComm_UMTS_Notification_Geolocation.png[image,width=750,height=400] + + + +Next diagram is the analogue of the latter, but for EPS networks or LTE location services (where SS7/MAP operations do not apply anymore, but their analogous Diameter procedures with EPC and E-UTRAN entities). + + + +image:images/RestComm_LTE_Notification_Geolocation.png[image,width=750,height=400] + +== Geolocation Status Callbacks Sequence Diagram + + +A Geolocation sequence diagram of RestComm API interacting with Location +Servers for most accurate location information retrieved to the Status +Callback URL when available. The sequence shown reveals the best case +scenario, where status callbacks are performed until the most accurate +positioning method available. As shown, last known stored location +information is initially returned. Afterwards, a better procedure +returns a more accurate location information based on the current access +point. Ultimately, the best possible available method (GPS) gathers the +location information and is delivered to the requesting application. +Accordingly, LastGeolocationResponse parameter is set to "true" in the +last status callback, as the desired accuracy is ultimately achieved. + + + +image:images/GeolocationStatusCallbacksSequenceDiagram.gif[image,width=633,height=348] + + + +== RestComm Core SS7 and LTE Geolocation Configuration + + +RestComm needs to be configured to be able to process Geolocation +services. The GMLC (Gateway Mobile Location Center) to which Restcomm +must send the Location request must be configured in _restcomm.xml_ +file. IP address and port configuration are mandatory. Username and +password are optional for GMLC. + +.... + + + + GMLC_IP:PORT_NUMBER + + + +.... diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/ElementTree-4.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/ElementTree-4.png new file mode 100644 index 0000000000..731c1fb987 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/ElementTree-4.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/GeolocationStatusCallbacksSequenceDiagram.gif b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/GeolocationStatusCallbacksSequenceDiagram.gif new file mode 100644 index 0000000000..3e5ea1e520 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/GeolocationStatusCallbacksSequenceDiagram.gif differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/IPGeolocationSequenceDiagram.gif b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/IPGeolocationSequenceDiagram.gif new file mode 100644 index 0000000000..2be1e66288 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/IPGeolocationSequenceDiagram.gif differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_GSM_Immediate_Geolocation.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_GSM_Immediate_Geolocation.png new file mode 100644 index 0000000000..abcf220676 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_GSM_Immediate_Geolocation.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_LTE_Notification_Geolocation.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_LTE_Notification_Geolocation.png new file mode 100644 index 0000000000..f76658dee9 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_LTE_Notification_Geolocation.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_UMTS_Notification_Geolocation.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_UMTS_Notification_Geolocation.png new file mode 100644 index 0000000000..60910e1d06 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/RestComm_UMTS_Notification_Geolocation.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.34.53.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.34.53.png new file mode 100644 index 0000000000..b616c8e2b4 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.34.53.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.35.37.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.35.37.png new file mode 100644 index 0000000000..c1e84f2ef4 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.35.37.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.40.46.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.40.46.png new file mode 100644 index 0000000000..05bdb171e1 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/Screen-Shot-2015-10-05-at-16.40.46.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/admin_ui_refer_url.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/admin_ui_refer_url.png new file mode 100644 index 0000000000..c00abb8798 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/admin_ui_refer_url.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/status-callback-events-dial.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/status-callback-events-dial.png new file mode 100644 index 0000000000..1e3bc72e62 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/images/status-callback-events-dial.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/incoming-phone-numbers-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/incoming-phone-numbers-api.adoc new file mode 100644 index 0000000000..edec7d6da9 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/incoming-phone-numbers-api.adoc @@ -0,0 +1,619 @@ += Restcomm API – Incoming Phone Numbers + +[[IncomingPhoneNumbers]] +== IncomingPhoneNumbers + +An IncomingPhoneNumber instance resource represents a Restcomm phone number + +The IncomingPhoneNumbers list resource represents an account's Restcomm phone numbers. You can POST to the list resource to provision a new Restcomm number. To find a new number to provision use the subresources of the AvailablePhoneNumbers resource. + +You can move phone numbers between two Restcomm accounts if you're using subaccounts. For details, see Exchanging Numbers Between Subaccounts. + +Provisioning a phone number is a two-step process. First, you must find an available phone number to provision using the subresources of the AvailablePhoneNumbers resource. Second, you must POST to the IncomingPhoneNumbers list resource, documented below. + +[[incomingphonenumber-instance-resource]] +=== IncomingPhoneNumber Instance Resource + +[[resource-uri]] +==== Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/IncomingPhoneNumbers/\{IncomingPhoneNumberSid}* + +[[resource-properties]] +==== Resource Properties + +[cols=",",] +|================================================================================================================================================================================================================================================== +|*Property* |*Description* +|Sid |A 34 character string that uniquely identifies this resource. +|DateCreated |The date that this resource was created, given as GMThttp://www.ietf.org/rfc/rfc2822.txt[RFC 2822] format. +|DateUpdated |The date that this resource was last updated, given as GMThttp://www.ietf.org/rfc/rfc2822.txt[RFC 2822] format. +|FriendlyName |A human readable descriptive text for this resource, up to 64 characters long. By default, the FriendlyName is a nicely formatted version of the phone number. +|AccountSid |The unique id of the Account responsible for this phone number. +|PhoneNumber |The incoming phone number. e.g., +16175551212 (http://en.wikipedia.org/wiki/E.164[E.164] format) +|ApiVersion |Calls to this phone number will start a new RCML session with this API version. +|VoiceCallerIdLookup |Look up the caller's caller-ID name from the CNAM database ($0.01 per look up). Either true or false. +|VoiceUrl |The URL Restcomm will request when this phone number receives a call. +|VoiceMethod |The HTTP method Restcomm will use when requesting the above Url. Either GET or POST. +|VoiceFallbackUrl |The URL that Restcomm will request if an error occurs retrieving or executing the RCML requested by Url. +|VoiceFallbackMethod |The HTTP method Restcomm will use when requesting the VoiceFallbackUrl. Either GET or POST. +|StatusCallback |The URL that Restcomm will request to pass status parameters (such as call ended) to your application. +|StatusCallbackMethod |The HTTP method Restcomm will use to make requests to the StatusCallback URL. Either GET or POST. +|VoiceApplicationSid |The 34 character sid of the application Restcomm should use to handle phone calls to this number. If a VoiceApplicationSid is present, Restcomm will ignore all of the voice urls above and use those set on the application. +|VoiceApplicationName |The application name. +|SmsUrl |The URL Restcomm will request when receiving an incoming SMS message to this number. +|SmsMethod |The HTTP method Restcomm will use when making requests to the SmsUrl. Either GET or POST. +|SmsFallbackUrl |The URL that Restcomm will request if an error occurs retrieving or executing the RCML from SmsUrl. +|SmsFallbackMethod |The HTTP method Restcomm will use when requesting the above URL. Either GET or POST. +|SmsApplicationSid |The 34 character sid of the application Restcomm should use to handle SMSs sent to this number. If a SmsApplicationSid is present, Restcomm will ignore all of the SMS urls above and use those set on the application. +|SmsApplicationName |The application name. +|UssdUrl |The URL Restcomm will request when receiving an incoming USSD request to this number. +|UssdMethod |The HTTP method Restcomm will use when making requests to the UssdUrl. Either GET or POST. +|UssdFallbackUrl |The URL that Restcomm will request if an error occurs retrieving or executing the RCML from UssdUrl. +|UssdFallbackMethod |The HTTP method Restcomm will use when requesting the above URL. Either GET or POST. +|UssdApplicationSid |The 34 character sid of the application Restcomm should use to handle USSD requests to this number. If a UssdApplicationSid is present, Restcomm will ignore all of the Ussd urls above and use those set on the application. +|UssdApplicationName |The application name. +|ReferUrl |The URL Restcomm will request when receiving a SIP Refer request to this number. +|ReferMethod |The HTTP method Restcomm will use when making requests to the ReferUrl. Either GET or POST. +|ReferApplicationSid |The 34 character sid of the application Restcomm should use to handle SIP Refer requests to this number. If a ReferApplicationSid is present, Restcomm will ignore all of the Refer urls above and use those set on the application. +|ReferApplicationName |The application name. +|Capabilities |This is a set of boolean properties that indicate whether a phone number can receive calls or messages. Possible capabilities are Voice, SMS, and MMS with each having a value of either true or false. +|Uri |The URI for this resource, relative to https://api.Restcomm.com. +|================================================================================================================================================================================================================================================== + + +[[http-methods]] +==== HTTP Methods + +[[http-get]] +===== HTTP GET + + +[[http-post-and-put]] +===== HTTP POST and PUT + +Tries to update the incoming phone number's properties, and returns the updated resource representation if successful. The returned response is identical to that returned above when making a GET request. + +[[optional-parameters]] +====== Optional Parameters + +You may specify one or more of the following parameters to update this phone number's respective properties: + +[cols=",",] +|========================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|FriendlyName |A human readable description of the new incoming phone number resource, with maximum length 64 characters. +|ApiVersion |Calls to this phone number will start a new RCML session with this API version - 2012-04-24 +|VoiceUrl |The URL that Restcomm should request when somebody dials the phone number. +|VoiceMethod |The HTTP method that should be used to request the VoiceUrl. Either GET or POST. +|VoiceFallbackUrl |A URL that Restcomm will request if an error occurs requesting or executing the RCML defined by VoiceUrl. +|VoiceFallbackMethod |The HTTP method that should be used to request the VoiceFallbackUrl. Either GET or POST. +|StatusCallback |The URL that Restcomm will request to pass status parameters (such as call ended) to your application. +|StatusCallbackMethod |The HTTP method Restcomm will use to make requests to the StatusCallback URL. Either GET or POST. +|VoiceCallerIdLookup |Do a lookup of a caller's name from the CNAM database and post it to your app. Either true or false. +|VoiceApplicationSid |The 34 character sid of the application Restcomm should use to handle phone calls to this number. If a VoiceApplicationSid is present, Restcomm will ignore all of the voice urls above and use those set on the application instead. +|SmsUrl |The URL that Restcomm should request when somebody sends an SMS to the new phone number. +|SmsMethod |The HTTP method that should be used to request the SmsUrl. Either GET or POST. +|SmsFallbackUrl |A URL that Restcomm will request if an error occurs requesting or executing the RCML defined by SmsUrl. +|SmsFallbackMethod |The HTTP method that should be used to request the SmsFallbackUrl. Either GET or POST. +|SmsApplicationSid |The 34 character sid of the application Restcomm should use to handle SMSs sent to this number. If a SmsApplicationSid is present, Restcomm will ignore all of the SMS urls above and use those set on the application instead. +|AccountSid |The unique 34 character id of the account to which you wish to transfer this phone number. +|========================================================================================================================================================================================================================================================== + +[[attributes-status-callback]] +==== statusCallback + +With IncomingPhoneNumber **statusCallback**, you can subscribe to receive webhooks for different events on the incoming phone number. + +The statusCallback events are: + + * RINGING + * IN_PROGRESS + * COMPLETED + +==== statusCallbackMethod + +The *statusCallbackMethod* attribute allows you to specify which HTTP method Restcomm should use when requesting the URL in the statusCallback attribute. The default is POST. + +==== Status Callback HTTP Parameters + +The parameters Restcomm passes to your application in its asynchronous request to the StatusCallback URL include all parameters passed in a synchronous request to retrieve RCML when Restcomm receives a call to one of your Restcomm numbers. The full list of parameters and descriptions of each are in the RCML Voice Request documentation. + +When the call progress events are fired, the Status Callback request also passes these additional parameters: + +[cols=",",options="header",] +|=================================================================================================================================================================================================================================================================== +|Parameter |Description +|CallSid |A unique identifier for this call, generated by Restcomm. You can use the `CallSid` to modify the child call by POSTing to Calls/\{CallSid} with a new RCML URL. +|InstanceId |A unique identifier for this Restcomm-Connect instance. +|OutboundCallSid | **optional** - A unique identifier for the outbound leg of this call +|AccountSid | A unique identifier of the account that this number belongs +|From | A string that describes the From address +|To | A string that describes the To address +|CallStatus |A descriptive status for the call. The value is one of **`ringing`**, **`in-progress`**, **`completed`**. +|ApiVersion | A string that describes the Restcomm-Connect REST API version +|Direction | A string that describes the direction of the call +|CallerName | **optional** A string that represents the callers name, if available +|ForwardedFrom | **optiona** A string that represents the number that the call was forwarded from +|CallTimestamp | A string the describe the timestamp of the call +|ReferTarget | **optional** A string that describes the transfer target, if this call started by a transfer +|Transferor | **optional** A string that describes the transferor, if this call started by a transfer +|Transferee | **optional** A string that describes the transferee, if this call started by a transfer +|DialSipCallId | **optional** The SIP Call-ID header value for final SIP Responses to the call +|DialSipResponseCode | **optional** The SIP response code for final SIP Responses to the call +|DialSipHeader_ | **optional** The SIP custome headers (if any) for final SIP Responses to the call +|=================================================================================================================================================================================================================================================================== + +[[http-delete]] +===== HTTP DELETE + +Release this phone number from your account. Restcomm will no longer answer calls to this number, and you will stop being billed the monthly phone number fee. The phone number will eventually be recycled and potentially given to another customer, so use with care. If you make a mistake, contact us. We may be able to give you the number back. If successful, returns an HTTP 204 response with no body. + +[[incomingphonenumbers-list-resource]] +=== IncomingPhoneNumbers List Resource + + +[[resource-uri-1]] +==== Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/IncomingPhoneNumbers* + +[[http-methods]] +==== HTTP Methods + +[[http-get-1]] +===== HTTP GET + +Returns a list of IncomingPhoneNumber resource representations, each representing a phone number given to your account. The list includes paging information. + +[[list-filters]] +====== List Filters + +The following query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +[cols=",",] +|============================================================================================================================================================ +|*Parameter* |*Description* +|PhoneNumber |Only show the incoming phone number resources that match this pattern. You can specify partial numbers and use '*' as a wildcard for any digit. +|FriendlyName |Only show the incoming phone number resources with friendly names that exactly match this name. +|Beta |Include phone numbers new to the Restcomm platform. Possible values are either true or false. Default is true. +|============================================================================================================================================================ + +====== Example - List of phone numbers + +Gets all numbers created using *IncomingPhoneNumbers.json* + +.... +curl -G https://\{account_sid}:\{auth_token}@127.0.0.1/restcomm/2012-04-24/Accounts/\{account_sid}/IncomingPhoneNumbers.json +.... + +Result of the above command + +.... +[ + { + "sid": "PN0b4201c6c87749f29367e6cf000686cb", + "account_sid": "\{account_sid}", + "friendly_name": "This app calls registered restcomm client Alice ", + "phone_number": "+1238", + "voice_url": "/restcomm/demos/dial/client/dial-client.xml", + "voice_method": "POST", + "voice_fallback_url": null, + "voice_fallback_method": "POST", + "status_callback": null, + "status_callback_method": "POST", + "voice_caller_id_lookup": false, + "voice_application_sid": null, + "date_created": "Mon, 4 Nov 2013 12:14:11 +0000", + "date_updated": "Mon, 4 Nov 2013 12:14:11 +0000", + "sms_url": null, + "sms_method": "POST", + "sms_fallback_url": null, + "sms_fallback_method": "POST", + "sms_application_sid": null, + "ussd_url": null, + "ussd_method": null, + "ussd_fallback_url": null, + "ussd_fallback_method": null, + "ussd_application_sid": null, + "refer_url": null, + "refer_method": null, + "refer_application_sid": null, + "capabilities": { + "voice_capable": true, + "sms_capable": false, + "mms_capable": false, + "fax_capable": false + }, + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/\{account_sid}/IncomingPhoneNumbers/PN0b4201c6c87749f29367e6cf000686cb.json" + },... + +.... + +[[http-post]] +===== HTTP POST + +Purchases a new phone number for your account. If a phone number is found for your request, Restcomm will add it to your account and bill you for the first month's cost of the phone number. If Restcomm cannot find a phone number to match your request, you will receive an HTTP 400 with Restcomm error code. To find an available phone number to POST, use the subresources of the AvailablePhoneNumbers list resource. + +[[required-parameters]] +====== Required Parameters + +Your request *must* include *exactly one* of the following parameters: + +[cols=",",] +|============================================================================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|PhoneNumber |The phone number you want to purchase. The number should be formatted starting with a '+' followed by the country code and the number inhttp://en.wikipedia.org/wiki/E.164[E.164] format e.g., '+15105555555'. *You must include either this or an AreaCode parameter to have your POST succeed.* +|AreaCode |The desired area code for your new incoming phone number. Any three digit, US or Canada area code is valid. Restcomm will provision a random phone number within this area code for you. *You must include either this or a PhoneNumber parameter to have your POST succeed.* (US and Canada only) +|============================================================================================================================================================================================================================================================================================================== + +If you include both parameters, we will use the AreaCode parameter and ignore the PhoneNumber provided. + +[[optional-parameters-1]] +====== Optional Parameters + +Your request may include the following parameters: + +[cols=",",] +|===================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|FriendlyName |A human readable description of the new incoming phone number. Maximum 64 characters. Defaults to a formatted version of the number. +|VoiceUrl |The URL that Restcomm should request when somebody dials the new phone number. +|VoiceMethod |The HTTP method that should be used to request the VoiceUrl. Must be either GET or POST. Defaults to POST. +|VoiceFallbackUrl |A URL that Restcomm will request if an error occurs requesting or executing the RCML at Url. +|VoiceFallbackMethod |The HTTP method that should be used to request the VoiceFallbackUrl. Either GET or POST. Defaults to POST. +|StatusCallback |The URL that Restcomm will request to pass status parameters (such as call ended) to your application. +|StatusCallbackMethod |The HTTP method Restcomm will use to make requests to the StatusCallback URL. Either GET or POST. Defaults to POST. +|VoiceCallerIdLookup |Do a lookup of a caller's name from the CNAM database and post it to your app. Either true or false. Defaults to false. +|VoiceApplicationSid |The 34 character sid of the application Restcomm should use to handle phone calls to the new number. If a VoiceApplicationSid is present, Restcomm will ignore all of the voice urls above and use those set on the application. +|SmsUrl |The URL that Restcomm should request when somebody sends an SMS to the phone number. +|SmsMethod |The HTTP method that should be used to request the SmsUrl. Must be either GET or POST. Defaults to POST. +|SmsFallbackUrl |A URL that Restcomm will request if an error occurs requesting or executing the RCML defined by SmsUrl. +|SmsFallbackMethod |The HTTP method that should be used to request the SmsFallbackUrl. Must be either GET or POST. Defaults to POST. +|SmsApplicationSid |The 34 character sid of the application Restcomm should use to handle SMSs sent to the new number. If a SmsApplicationSid is present, Restcomm will ignore all of the SMS urls above and use those set on the application. +|ApiVersion |The Restcomm REST API version to use for incoming calls made to this number. If omitted, uses 2012-04-24. +|===================================================================================================================================================================================================================================================== + +If successful, Restcomm responds with a representation of the new phone number that was assigned to your account.   + +[[http-put]] +===== HTTP PUT + +Not Supported. + +[[http-delete-1]] +===== HTTP DELETE + +Not Supported. + +[[local-incomingphonenumber-factory-resource]] +=== Local IncomingPhoneNumber Factory Resource + +POSTing to this resource allows you to request a new local phone number be added to your account. This subresource represents only Local phone numbers. + +[[resource-uri-2]] +==== Resource URI + +*/2012-04-24/Accounts/\{YourAccountSid}/IncomingPhoneNumbers/Local* + +[[http-methods]] +==== HTTP Methods + +[[http-get-2]] +===== HTTP GET + +Returns a list of local elements, each representing a local (not toll-free) phone number given to your account, under an list element that includes paging information. Works exactly the same as the IncomingPhoneNumber resource, but filters out toll-free numbers. + +[[http-post-1]] +===== HTTP POST + +Adds a new phone number to your account. If a phone number is found for your request, Restcomm will add it to your account and bill you for the first month's cost of the phone number. If Restcomm can't find a phone number to match your request, you will receive an HTTP 400 with Restcomm error code. To find an available phone number to POST, use the subresources of the AvailablePhoneNumbers list resource. + +[[required-parameters-1]] +====== Required Parameters + +Your request *must* include PhoneNumber. We do not support AreaCode for this subresource: + +[cols=",",] +|============================================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|PhoneNumber |The phone number you want to purchase. The number should be formatted starting with a '+' followed by the country code and the number inhttp://en.wikipedia.org/wiki/E.164[E.164] format e.g., '+15105555555'. *You must include this to have your POST succeed.* +|============================================================================================================================================================================================================================================================================== + +[[optional-parameters-2]] +====== Optional Parameters + +The optional parameters for this request are exactly the same as POSTing directly to the IncomingPhoneNumbers/ resource. If successful, Restcomm responds with a representation of the new phone number that was assigned to your account.   + +[[http-put-1]] +===== HTTP PUT + +Not Supported. + +[[http-delete-2]] +===== HTTP DELETE + +Not Supported. + +[[toll-free-incomingphonenumber-factory-resource]] +=== Toll-Free IncomingPhoneNumber Factory Resource + +This subresource represents only toll-free phone numbers. POSTing to this resource allows you to request a new toll-free phone number be added to your account. + +[[resource-uri-3]] +==== Resource URI + +*/2012-04-24/Accounts/\{YourAccountSid}/IncomingPhoneNumbers/TollFree* + +[[http-methods-1]] +==== HTTP Methods + +[[http-get-3]] +===== HTTP GET + +Returns a list of local elements, each representing a toll-free phone number given to your account, under an list element that includes paging information. Works exactly the same as the IncomingPhoneNumber resource, but filters out all numbers that aren't toll-free. + +[[http-post-2]] +===== HTTP POST + +Adds a new phone number to your account. If a phone number is found for your request, Restcomm will add it to your account and bill you for the first month's cost of the phone number. If Restcomm can't find a phone number to match your request, you will receive an HTTP 400 with Restcomm error code. To find an available phone number to POST, use the subresources of the AvailablePhoneNumbers list resource. + +[[required-parameters-2]] +====== Required Parameters + +Your request *must* include PhoneNumber. We do not support AreaCode for this subresource: + +[cols=",",] +|=========================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|PhoneNumber |The phone number you want to purchase. The number should be formatted starting with a '+' followed by the country code and the number in E.164 format e.g., '+15105555555'. *You must include this to have your POST succeed.* +|=========================================================================================================================================================================================================================================== + +[[optional-parameters-3]] +====== Optional Parameters + +The optional parameters for this request are exactly the same as POSTing directly to the IncomingPhoneNumbers/ resource. If successful, Restcomm will respond with a representation of the new phone number that was assigned to your account.   + +[[http-put-2]] +===== HTTP PUT + +Not Supported. + +[[http-delete-3]] +===== HTTP DELETE + +Not Supported. + +[[mobile-incomingphonenumber-factory-resource]] +=== Mobile IncomingPhoneNumber Factory Resource + +POSTing to this resource allows you to request a new mobile phone number be added to your account. This subresource represents only mobile phone numbers, i.e. not toll free numbers or local numbers. + +[[resource-uri-4]] +==== Resource URI + +*/2012-04-24/Accounts/\{YourAccountSid}/IncomingPhoneNumbers/Mobile* + +[[http-methods-2]] +==== HTTP Methods + +[[http-get-4]] +===== HTTP GET + +Returns a list of local elements, each representing a mobile phone number given to your account, under an list element that includes paging information. Works exactly the same as the IncomingPhoneNumber resource, but filters out local and toll free numbers. + +[[http-post-3]] +===== HTTP POST + +Adds a new phone number to your account. If a phone number is found for your request, Restcomm will add it to your account and bill you for the first month's cost of the phone number. If Restcomm can't find a phone number to match your request, you will receive an HTTP 400 with Restcomm error code. To find an available phone number to POST, use the subresources of the AvailablePhoneNumbers list resource. + +[[required-parameters-3]] +====== Required Parameters + +Your request *must* include PhoneNumber. We do not support AreaCode for this subresource: + +[cols=",",] +|============================================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|PhoneNumber |The phone number you want to purchase. The number should be formatted starting with a '+' followed by the country code and the number inhttp://en.wikipedia.org/wiki/E.164[E.164] format e.g., '+15105555555'. *You must include this to have your POST succeed.* +|============================================================================================================================================================================================================================================================================== + +[[optional-parameters-4]] +====== Optional Parameters + +The optional parameters for this request are exactly the same as POSTing directly to the IncomingPhoneNumbers/ resource. If successful, Restcomm will respond with a representation of the new phone number that was assigned to your account.   + +[[http-put-3]] +===== HTTP PUT + +Not Supported. + +[[http-delete-4]] +===== HTTP DELETE + +Not Supported.   + +== Attach a phone number to an application + +=== Attach a DID phone number to an application + +This one uses the default application + +.... +curl -X POST https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers.json -d "PhoneNumber=+15105555555" -d "VoiceUrl=https://127.0.0.1/restcomm/demos/hello-play.xml" +.... + +Result of the above command + +.... +{ + "sid": "PNdd7a0a0248244615978bd5781598e5eb", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "friendly_name": "15105555555", + "phone_number": "+15105555555", + "voice_url": "https://127.0.0.1/restcomm/demos/hello-play.xml", + "voice_method": "POST", + "voice_fallback_method": "POST", + "status_callback_method": "POST", + "voice_caller_id_lookup": false, + "date_created": "2013-10-04T17:42:02.500-06:00", + "date_updated": "2013-10-04T17:42:02.500-06:00", + "sms_method": "POST", + "sms_fallback_method": "POST", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb.json" + +.... + +IMPORTANT: If you are trying to attach a number that you didn't look up previously from <> ie if you want to attach a number that is Virtual (SIP Number) and not attached to a particular DID provider, you need to add -D "isSIP=true" as show below + +=== Attach a SIP Virtual number to an application + +This one uses the default application + +.... +curl -X POST https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers.json -d "PhoneNumber=1234" -d "VoiceUrl=https://127.0.0.1/restcomm/demos/hello-play.xml" -d "isSIP=true" +.... + +Result of the above command + +.... +{ + "sid": "PNdd7a0a0248244615978bd5781598e5eb", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "friendly_name": "234", + "phone_number": "+1234", + "voice_url": "https://127.0.0.1/restcomm/demos/hello-play.xml", + "voice_method": "POST", + "voice_fallback_method": "POST", + "status_callback_method": "POST", + "voice_caller_id_lookup": false, + "date_created": "2013-10-04T17:42:02.500-06:00", + "date_updated": "2013-10-04T17:42:02.500-06:00", + "sms_method": "POST", + "sms_fallback_method": "POST", + "api_version": "2012-04-24", + "uri": "/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb.json" + +.... + +== Delete a phone number + +You have to get the SID of the phone and use curl to delete as follows + +.... +curl -X DELETE https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers/PNdd7a0a0248244615978bd5781598e5eb +.... + +== List of phone numbers + +Gets all numbers created using *IncomingPhoneNumbers.json* + +.... +curl -X GET https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/IncomingPhoneNumbers.json +.... + +== Incoming Phone Number Regex Support + +=== Logic +The following diagram depicts the main logic regarding incoming phone numbers, +and regular expressions during an actual call: + +[plantuml,Regex Logic] +.... +:Retrieve Number from DB (In IncomingOrganization); + +if (Number Matched?) then (yes) + :Trigger linked Application; +else (no) + if (IncomingOrganization != null?) then (yes) + :Retrieve Regexes In IncomingOrganization; + :Sort Regexes by Length; + repeat + if (Number Matched?) then (yes) + :Trigger linked Application; + endif + repeat while (more regexes || !matched?) + else (no) + :No application found; + endif +endif + +.... + + +As we can see, the perfect match against the incoming number will be attempted +first. Then, if no matching is found the regular expressions associated to the +Organization will be evaluated. + +WARNING: Watch out, Regex has been disabled for incoming SMPP/SMS messages because SMPP is not supporting Organizations. + + +=== Regular Expression examples + +The following table provides examples on how the logic is exercised depending on current +contents of DB. +|=== +|*IncomingPhoneNumber*|*DB Table*|*Description* +| 16508251255 | "16508251255" "16.*" | Perfect match against "16508251255" +| 16508251255 | "16508251256" "16.*" | No Perfect match found. regex "16.*" applies +| 16508251255 | "16508251256" "16.+++*+++","16508.+++*+++" | No Perfect match found. longest regex "16508.*" applies +|=== + + +The following table provides examples on how a single regular expression may +match different numbers. + +|=== +|*Regex Sample* |*Description* +|7777\|8888 | Matches the numbers 7777 or 8888 +|^*77...33#$| Matches any number that starts with *77 and and the three dots matches any character and it must end with a # sign +|^[12]2233#$| Matches any number that starts with 1 or 2 and ends with 2233# +|^7688[456]#$ | matches any number that starts with 76884# or 76885# or 76886# +|[45]234[23] | matches 42342, 42343, 52342 and 52343 +|^*222*...*...*500#$| the Regext (^*222*...*...*500#$) matches *222*888*999*500# or *222*444*321*500# the dots maches any character +|999...| Matches 999222, 999123, 999555 the dots matches any character +|=== + + + +[[resource-uri-5]] +==== Resource URI + +*/2012-04-24/Accounts/\{TargetAccountSid}/IncomingPhoneNumbers/migrate* + +[[http-methods-2]] +==== HTTP Methods + +[[http-post-3]] +===== HTTP POST + +Migrates all numbers of `TargetAccountSid's` account tree to provided destination organization. +Only super admins have permission to perform this operation. +[NOTE] +==== +This operation will impact all child accounts in downwards hierarchy. +==== + + +[[required-parameters-3]] +====== Required Parameters + +Your request *must* include OrganizationSid. + +[cols=",",] +|============================================================================================================================================================================================================================================================================== +|*Parameter* |*Description* +|OrganizationSid | Sid of destination organization, where we want to migrate numbers. +|============================================================================================================================================================================================================================================================================== + +[[http-put-3]] +===== HTTP PUT + +Not Supported. + +[[http-delete-4]] +===== HTTP DELETE + +Not Supported.   \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/index.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/index.adoc new file mode 100644 index 0000000000..736706f081 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/index.adoc @@ -0,0 +1,44 @@ += Restcomm Rest API + +The Restcomm REST API allows you to query meta-data about your account, phone numbers, calls, text messages, and recordings. You can also do some communications control like initiate outbound calls and send text messages. + +== Base URL + +All URLs referenced in the documentation have the following base: + +https://cloud.restcomm.com/restcomm/2012-04-24 + +The Restcomm REST API is served over HTTPS. To ensure data privacy, unencrypted HTTP is not supported. + +== Sub-Resources + +Restcomm Accounts have the following subresources. Click on a link to read the API documentation for accessing or modifying each resource: + +=== Developer Sub-Resources + +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> + +=== Management Sub-Resources + +* <> +* <> +* <> +* <> diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/monitoring-service.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/monitoring-service.adoc new file mode 100644 index 0000000000..c751242651 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/monitoring-service.adoc @@ -0,0 +1,124 @@ +[[monitoring]] += Restcomm API - Supervisor/Monitoring service + +== Supervisor API +You can use *Supervisor API* to access statistics from Restcomm and monitor the usage. + +*Supervisor API* can be used to monitor traffic on a Restcomm instance. + +The *Supervisor API* will provide the following metrics: + +* Real Time metrics + - Live incoming calls + - Live outgoing calls + - Live calls (total) + - Live call details array. An array with call details for each of the live calls + - Registered users +* Accumulated metrics + - Total calls since uptime + - Incoming calls since uptime + - Outgoing calls since uptime + - No Answered calls + - Busy calls + - Failed calls + - Not found calls + - Canceled calls + - Inbound Text messages to RMCL applications + - Inbound Text messages to Restcomm clients + - Inbound Text messages to outbound proxy + - Inbound Text messages with Not Found error + - Outoing Text messages + +=== Supervisor Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Supervisor.json/metrics* + +Will return MonitoringService metrics. + +Supervisor API supports only json format. + +=== Resource Properties + +[cols=",",options="header",] +|====================================================================================================================================================================== +|Property |Description +|LiveCallDetails | (optional) Set to *true* to get an array of live calls. Default value *false* +|====================================================================================================================================================================== + +=== Supported Operations +**HTTP GET**. Returns the monitoring service metrics in json format. + +=== Supervisor Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Supervisor.json/livecalls* + +Will return array of live calls (if any) + +Supervisor API supports only json format. + +=== Supported Operations +**HTTP GET**. Returns the monitoring service metrics in json format. + +=== Get metrics + +To get the monitoring service metrics you can use the curl command bellow + +.... +curl https://ACCOUNT_ID:AUTH_TOKEN@IP_ADDRESS/restcomm/2012-04-24/Accounts/ACCOUNT_ID/Supervisor.json/metrics +.... + +For example for the curl command below: + +.... +curl https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Supervisor.json/metrics?LiveCallDetails=true +.... + +the monitoring service response for a Restcomm instance with 1 registered user and 2 live calls will return the following metrics: + +.... +{ + { + "InstanceId": "ID6f1e138741034df5879be5e073b018bb", + "Version": "7.7.0", + "Revision": "rccfa3f2159ddcabdac430de17aec05f9b0a6ea2e", + "Metrics": { + "TotalCallsSinceUptime": 4, + "NoAnswerCalls": 0, + "LiveOutgoingCalls": 0, + "OutgoingCallsSinceUptime": 0, + "IncomingCallsSinceUptime": 4, + "RegisteredUsers": 1, + "CompletedCalls": 2, + "TextMessageOutbound": 0, + "NotFoundCalls": 0, + "CanceledCalls": 0, + "FailedCalls": 0, + "TextMessageNotFound": 0, + "TextMessageInboundToApp": 0, + "LiveCalls": 2, + "BusyCalls": 0, + "LiveIncomingCalls": 2, + "TextMessageInboundToProxyOut": 0, + "TextMessageInboundToClient": 0 + }, + "LiveCallDetails": [ + { + "sid": "CA1c34db0d7ba1488a9c7eefaadc982358", + "State": "IN_PROGRESS", + "direction": "inbound", + "date_created": "Mon, 30 May 2016 13:47:52 +0300", + "from": "bob", + "to": "1310", + "Initial Invite": "sip:1310@127.0.0.1:5080" + }, + { + "sid": "CAb9fecafc42cc4ad49e0dd991f1966cc7", + "State": "IN_PROGRESS", + "direction": "inbound", + "date_created": "Mon, 30 May 2016 13:47:48 +0300", + "from": "unregistereduser", + "to": "1310", + "Initial Invite": "sip:1310@127.0.0.1:5080" + } + ] +.... diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/notifications-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/notifications-api.adoc new file mode 100644 index 0000000000..07674fe996 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/notifications-api.adoc @@ -0,0 +1,216 @@ += Restcomm API – Notifications + +[[Notifications]] +== Notifications + +A *Notification* resource represents a single log entry made by RestComm while handling your calls or your use of the Restful APIs. It is very useful for debugging purposes. The Notifications list resource represents the set of notifications generated for an account. + +=== Notification Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Notifications/\{NotificationSid}* + +==== Resource Properties + +[cols=",",options="header",] +|=============================================================================================================================================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this transcription. +|DateCreated |The date that this transcription was created. +|DateUpdated |The date that this transcription was last updated. +|AccountSid |The unique id of the Account that created this transcription. +|CallSid |CallSid is the unique id of the call during which the notification was generated. Empty if the notification was generated by the Restful APIs without regard to a specific phone call. +|ApiVersion |The RestComm API version in use when this notification was generated. May be empty for events that don't have a specific API version. +|Log |An integer log level corresponding to the type of notification: 0 is ERROR, 1 is WARNING. +|ErrorCode |A unique error code for the error condition. You can lookup errors, in our Error Dictionary. +|MoreInfo |A URL for more information about the error condition. The URL is a page in our Error Dictionary. +|MessageText |The text for the notification. +|MessageDate |The date the notification was actually generated +|RequestUrl |The URL of the resource that caused the notification to be generated. +|RequestMethod |The HTTP method in use for the request that caused the notification to be generated. +|RequestVariables |The HTTP GET or POST variables that RestComm generated and sent to your server. Also, if the notification was generated by the Restful APIs, this field will include any HTTP POST or PUT variables you sent. +|ResponseHeaders |The HTTP headers returned by your server. +|ResponseBody |The HTTP body returned by your server. +|Uri |The URI for this account, relative to https://localhost/restcomm. +|=============================================================================================================================================================================================================================== + +==== Supported Operations + +**HTTP GET**. Returns the representation of a Notification resource, including the properties above.Notification List Resource + +=== Notification List Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Notifications* + +==== Supported Operations + +**HTTP GET**. Returns the list representation of all the Notification resources for this Account, including the properties above. + +== Get list of Notifications + +To retrieve a list of notification run the following command from a bash terminal: + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications +.... + +[[example-get-response]] +== Example GET Response + +=== JSON GET Response + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json +---- + + +---- +{"page":0,"num_pages":0,"page_size":50,"total":34,"start":"0","end":"34","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=0&PageSize=50","notifications": + [ + { + "sid":"RF10000000000000000000000000000001", + "date_created":"Fri, 30 Aug 2013 16:28:33 +0900", + "date_updated":"Fri, 30 Aug 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CA5EB00000000000000000000000000002", + "api_version":"2012-04-24", + "log":1, + "error_code":0, + "more_info":"http://docs.telestax.com/rvd-workspace-upgrade", + "message_text":"Workspace migration skipped in 2016-12-28 21:12:25.758", + "message_date":"2013-08-30T16:28:33.403+09:00", + "request_url":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav", + "request_method":"request method", + "request_variables":"request variable", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications/NOb88ccff6c9e04f989de9415a555ad84d.json.json"} + }, + ... + ] +} +---- +  + +== List Filter + +**HTTP GET**. The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================================== +|Parameter |Description +|StartTime |Only show notifications that started on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for notifications that started at or before midnight on a date, and StartTime=YYYY-MM-DD for notifications that started at or after midnight on a date. +|EndTime |Only show notifications that ended on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for notifications that started at or before midnight on a date, and StartTime=YYYY-MM-DD for notifications that started at or after midnight on a date. +|ErrorCode |Only show notifications that returned this Error Code +|RequestUrl |Only show notifications that have this RequestUrl +|MessageText |Only show notifications that contain this MessageText. +|=========================================================================================================================================================================================================================================================================== + +  + +=== Filter using the ErrorCode parameter + +The example below will only return Messages sent from client Alice + +.... + curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?ErrorCode=1 +.... + +The result will be similar to the one below + +[source] +---- +{"page":0,"num_pages":0,"page_size":50,"total":19,"start":"0","end":"19","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=0&PageSize=50","notifications": + [ + { + "sid":"RF10000000000000000000000000000001", + "date_created":"Fri, 30 Aug 2013 16:28:33 +0900", + "date_updated":"Fri, 30 Aug 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CA5EB00000000000000000000000000002", + "api_version":"2012-04-24", + "log":1, + "error_code":1, + "more_info":"http://docs.telestax.com/rvd-workspace-upgrade", + "message_text":"Workspace migration skipped in 2016-12-28 21:12:25.758", + "message_date":"2013-08-30T16:28:33.403+09:00", + "request_url":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav", + "request_method":"request method", + "request_variables":"request variable", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications/NOb88ccff6c9e04f989de9415a555ad84d.json.json"} + }, + ... + ] +} +---- + +== Paging Information + +*HTTP GET.* The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|PParameter |Description +|Page |The current page number. Zero-indexed, so the first page is 0. +|NumPages |The total number of pages. +|PageSize |How many items are in each page +|Total |The total number of items in the list. +|Start |The position in the overall list of the first item in this page. +|End |The position in the overall list of the last item in this page. +|======================================================================= + +  + +=== Example. + +The command below will return a single item from the list of notifications using the PageSize parameter + +.... +curl -X GET http://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?PageSize=1 +.... + +The result of the *PageSize* parameter + +[source] +---- +{"page":0,"num_pages":34,"page_size":1,"total":34,"start":"0","end":"0","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=0&PageSize=1","previous_page_uri":"null","next_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=1&PageSize=1&AfterSid=RF10000000000000000000000000000001","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications.json?Page=34&PageSize=1","notifications": + [ + { + "sid":"RF10000000000000000000000000000001", + "date_created":"Fri, 30 Aug 2013 16:28:33 +0900", + "date_updated":"Fri, 30 Aug 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CA5EB00000000000000000000000000002", + "api_version":"2012-04-24", + "log":1, + "error_code":1, + "more_info":"http://docs.telestax.com/rvd-workspace-upgrade", + "message_text":"Workspace migration skipped in 2016-12-28 21:12:25.758", + "message_date":"2013-08-30T16:28:33.403+09:00", + "request_url":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav", + "request_method":"request method", + "request_variables":"request variable", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Notifications/NOb88ccff6c9e04f989de9415a555ad84d.json.json"} + } + ] +} +---- + +  + +== Additional Paging Information. + +The API returns URIs to the next, previous, first and last pages of the returned list as shown in the table below: + +=== Request Parameters + +[cols=",",options="header",] +|============================================================ +|Parameter |Description +|Uri |The URI of the current page. +|Firstpageuri |The URI for the first page of this list. +|Nextpageuri |The URI for the next page of this list. +|Previouspageuri |The URI for the previous page of this list. +|Lastpageuri |The URI for the last page of this list. +|============================================================ \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/organization-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/organization-api.adoc new file mode 100644 index 0000000000..0501e7b5f6 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/organization-api.adoc @@ -0,0 +1,137 @@ += Restcomm API – Organizations + +[[Organizations]] +== Organizations +Organization are useful for segmenting accounts and providing restcomm functionalities on custom domain name. + +=== Organization Api + +Organization api will provide functionality to perform CRUD (create, read, update and delete) operations for organizations. Api is mainly responsible for communicating with configureable DNS hosting service provider (for example Route-53 or others) for making changes in record sets. + +==== Organization Entity + +|==== +| Property | Description +| sid | A string that uniquely identifies this organization. +| domain_name | A custom DNS hostname that you create on Restcomm Cloud. It can accept traffic for an account. If anyone makes a SIP/HTTP request using that domain, say the SIP URI sip:alice@mycompany.restcomm.com, it will route to Restcomm. + +Total Length of domain_name can be upto 255 Characters. It can contain only letters, number and “-†aka hyphen sign. +| date_created | The date that this organization was created. +| date_updated | The date that this organization was last updated. +| Status | Active or Closed. +|==== + +==== Create new organization + +===== Rationale + +Rational to create a new organization pretty simple and described already, we want to onboard a new customer and provide them with their own domain and account on the platform. + +[source,] +---- +/{Version}/Organizations/{domainName} +---- + +HTTP PUT to above Uri will create a new organization and returns the representation of the organization resource, including the properties above. + +===== Uri Parameters + +|==== +| Property | Description +| domainName | A custom DNS hostname that you create on Restcomm Cloud. It can accept traffic for an account. If anyone makes a SIP/HTTP request using that domain, say the SIP URI sip:alice@mycompany.restcomm.com, it will route to Restcomm. + +Total Length of domain_name can be upto 255 Characters. It can contain only letters, number and “-†aka hyphen sign. +|==== + +.Add new organization with domain name "test" - Example +==== +curl -X PUT "https://:@mycompany.restcomm.com/restcomm/2012-04-24/Organizations/test" + + + OR905d1b4e9d3045acb268f8d0fdf259ac + test.restcomm.com. + active + Thu, 28 Sep 2017 16:11:39 +0000 + Thu, 28 Sep 2017 16:11:39 +0000 + +==== + +===== Optional Request Parameters + +|==== +| Property | Description +| HostedZoneId | ID of hosted zone on your DNS server, under which you want to create above domainName, if not provided system will use default configured one. +|==== + +.Add new organization with domain name "test" under a specific hosted zone - Example +==== +curl -X PUT "https://:@mycompany.restcomm.com/restcomm/2012-04-24/Organizations/test" -d "HostedZoneId=" + + + OR905d1b4e9d3045acb268f8d0fdf259ac + test.restcomm.com. + active + Thu, 28 Sep 2017 16:11:39 +0000 + Thu, 28 Sep 2017 16:11:39 +0000 + +==== + + +==== Read organization + +An account can read organization details if it belongs to that particular organization. Super admins can read all organizations. + +Read organization resource will return organization entity provided above. + +===== Single Resource URI + +Will return single organization resource + +[source,] +---- +/{Version}/Organizations(.json)/{OrganizationSid} +---- + +.Read Organization Example +==== +curl -X GET "https://{accountSid}:{authToken}@mycompany.restcomm.com/restcomm/2012-04-24/Organizations/{OrganizationSid}" + + + + OR905d1b4e9d3045acb268f8d0fdf259ac + test.restcomm.com. + active + Thu, 28 Sep 2017 16:11:39 +0000 + Thu, 28 Sep 2017 16:11:39 +0000 + +==== + +.Read Organization Json Example +==== +curl -X GET "https://{accountSid}:{authToken}@mycompany.restcomm.com/restcomm/2012-04-24/Organizations.json/{OrganizationSid}" +==== + +===== List Resource URI + +Will return list of organizations + +[source,] +---- +/{Version}/Organizations(.json) +---- + +===== List Filter + +You can filter an organization list resource by providing following parameters. + +===== Request Parameters + +|==== +| Property | Description +| Status | Active or Closed. +|==== + +.Read Organization List with filter Example +==== +curl -X GET "https://{accountSid}:{authToken}@mycompany.restcomm.com/restcomm/2012-04-24/Organizations/{OrganizationSid}.json" -d "Status=active" +==== diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/outbound-proxy-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/outbound-proxy-api.adoc new file mode 100644 index 0000000000..be04d152c8 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/outbound-proxy-api.adoc @@ -0,0 +1,17 @@ += Restcomm API – Outbound Proxy + +[[OutboundProxy]] +== OutboundProxy + +Using *Outbound proxy* endpoint you can get the details of Primary and Backup outbound proxy, get the current active outbound proxy and also switch outbound proxy. + +=== OutboundProxy Resource URI. + +*/2012-04-24/Accounts/\{accountSid}/OutboundProxy* + +==== Supported Operations + +*HTTP GET* Returns the list of outbound proxies. + +* HTTP GET */2012-04-24/Accounts/\{accountSid}/OutboundProxy/switchProxySwitch* the outbound proxy and returns the proxy in use +* HTTP GET */2012-04-24/Accounts/\{accountSid}/OutboundProxy/getActiveProxyReturns* the currently active outbound proxy diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/participants-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/participants-api.adoc new file mode 100644 index 0000000000..eab704cbf0 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/participants-api.adoc @@ -0,0 +1,129 @@ +[[participantsapi]] += Restcomm API – Participants + +== Participants + +A *Participant* represents a single participant currently connected to a running conference. It is idefiable by its CallSid. + +=== Participant Resource URI + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid} +.... + +=== Resource Properties + +[cols=",",options="header",] +|====================================================================================================================================================================== +|Property |Description +|CallSid |A string that uniquely identifies this particpant. +|ConferenceSid |A string that uniquely identifies the conference this particpant is currently connected in. +|DateCreated |The date that this particpant was created. +|DateUpdated |The date that this particpant was last updated. +|AccountSid |The unique id of the Account that created this call. +|Muted |Represents the flag if particpant is currently muted or not (*true* or *false*)? +|StartConferenceOnEnter |Represents if *StartConferenceOnEnter* flag was set for this particpant (*true* or *false*)? +|EndConferenceOnExit |Represents if *EndConferenceOnExit* flag was set for this particpant (*true* or *false*)? +|Uri |The URI for this account, relative to http://localhost:port/restcomm. +|====================================================================================================================================================================== + +=== Supported Operations +**HTTP GET**. Returns the representation of a Participant resource, including the properties above. + +**HTTP POST** to a Participant to mute/unmute a live Participant, we make an *HTTP POST* request to a live Participant instance resource URI: + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid} +.... + +or + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}.json +.... + +The following parameters are available for you to *POST* request.: + +=== Request Parameters + +[cols=",",options="header",] +|=================================================================================================================================================================================================================================================== +|Parameter |Description +| Mute | Either *true* or *flase*. Setting value of this parameter to *true* will mute the call. Setting value of this parameter to *false* will unmute the call. +|=================================================================================================================================================================================================================================================== + + + +**HTTP PUT**. +Not supported + +**HTTP DELETE**. +Not supported + +== Participant List Resource URI + +.... +/2012-04-24/Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants +.... + +=== Supported Operations +**HTTP GET**. Returns the list representation of all the Participant resources for this Account, including the properties above. + +**HTTP POST** +Not supported + +**HTTP PUT**. +Not supported + +**HTTP DELETE**. +Not supported + +=== Examples + +You can Mute/unMute an inprogress call as shown bellow. + +.Mute a Participant +==== +curl -X POST http://:@/restcomm/2012-04-24/Accounts//Conferences//Participants/ -d "Mute=true" +==== + +*Sample Mute Response* +---- + + + CA02b649d3ffe24408a1e141be089f347b + CFcc373b0637114f088eae954fa73f0f57 + Wed, 15 Mar 2017 10:10:57 +0000 + Wed, 15 Mar 2017 10:15:33 +0000 + ACae6e420f425248d6a26948c17a9e2acf + true + false + true + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA02b649d3ffe24408a1e141be089f347b + + +---- + +.unMute a Muted Participant +==== +curl -X POST http://:@/restcomm/2012-04-24/Accounts//Conferences//Participants/ -d "Mute=false" +==== + +*Sample unMute Response* +---- + + + CA02b649d3ffe24408a1e141be089f347b + CFcc373b0637114f088eae954fa73f0f57 + Wed, 15 Mar 2017 10:10:57 +0000 + Wed, 15 Mar 2017 10:16:44 +0000 + ACae6e420f425248d6a26948c17a9e2acf + false + false + true + false + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/CA02b649d3ffe24408a1e141be089f347b + + +---- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/profile-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/profile-api.adoc new file mode 100644 index 0000000000..8391c3c949 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/profile-api.adoc @@ -0,0 +1,234 @@ += Restcomm API – Profile + +[[Profiles]] +== Profiles + +Profiles allow to associate behavior configuration to specific Accounts or Organizations. Once a Profile +is associated with such Entity, the next session (USSD/Voice/SMS) attempt related to that +Entity will use the Profile configuration to tweak the service logic behavior. + +During session creation the service logic will try to find the associated Profile +based on this criteria, until a Profile is found: + +. Profile associated to current Account +. Profile associated to parent Account +. Profile associated to related Organization +. Default Profile + +The Default Profile is pre-provisioned in the system, and can't be modified from the +REST API. The Default Profile Sid is "PRae6e420f425248d6a26948c17a9e2acf" + +Since the Profile configuration is expected to grow as required, the Profile entity +is defined by a JSON schema, rather than regular properties, representing a +document used as generic container. + +=== Profile Resource URI + +*/2012-04-24/Profiles/\{ProfileSid}* + +=== Resource Schema +.... +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "resource:/org/restcomm/connect/http/schemas/rc-profile-schema.json#", + "additionalProperties": false, + "type": "object", + "properties": { + "featureEnablement": { + "$ref": "rc-feature-enablement-schema.json#/definitions/featureEnablement" + } + } +} +.... + +=== Supported Operations + +*HTTP GET.* Returns the representation of a Profile resource. + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|200 OK | Body contains Profile JSon document +|403 Forbidden |Only Super Admin is allowed to query Profiles +|404 Not Found |Target Profile SID is missing +|============================================================================================== + +==== Response Headers +[cols=",",options="header",] +|============================================================================================== +|Header |Description +|Link | a link to the Profile schema with "rel" "describedBy" +|Modified-Since | Date of last modification of the profile. +|============================================================================================== + + + +**HTTP PUT**. +Modifies a Profile resource and returns the representation. +The body of the request is expected to contain a JSON document compliant to the Profile +schema. + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|200 OK | Modification performed. Body contains Profile JSon document +|403 Forbidden |Only Super Admin is allowed to modify a Profile. DefaultProfile can't be modified +|404 Not Found |Target Profile SID is missing +|400 Bad Request | Body contains a Profile not compliant with schema +|============================================================================================== + +**HTTP DELETE** + +Removes an existing Profile, removing any existing association with Accounts/Organizations. + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|200 OK | Profile removed +|403 Forbidden |Only Super Admin is allowed to remove. DefaultProfile can't be deleted +|404 Not Found |Target Profile SID is missing or Link is not found +|============================================================================================== + +**HTTP LINK/UNLINK** + +Profile association operation maybe performed against a particular Account or Organization. +This operation will use HTTP 1.1 LINK/UNLINK methods, and target resource should be populated +in a Link header, using "related" as "rel" attribute. Only one Link header is supported. +To associate a single Profile with multiple Accounts/Organizations, multiple requests will be required. + + +==== Request Headers +[cols=",",options="header",] +|============================================================================================== +|Header |Description +|Link |Contains an full URL to the Account/Organization that should be associated to the Profile +|============================================================================================== + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|200 OK | Association established +|403 Forbidden |Only Super Admin is allowed for the association operation +|404 Not Found |Target Profile SID is missing or Link is not found +|400 Bad Request | None or multiple Link header provided. Link with unsupported "rel". +|============================================================================================== + + +**Get information about the default profile.** + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2acf +.... +**Add a new Profile.** + +.... +curl -X POST -H 'Content-Type: application/instance+json' --data "@/path/to/filename" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles +.... + +**Modify a Profile.** + +To update a Profile you need to provide the Profile SID + +For example, update Proile using sid: +.... +curl -X PUT -H 'Content-Type: application/instance+json' --data "@/path/to/filename" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +.... +curl -X GET https://administrator%40company.com:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +The above command will print an output similar to the one below: + +---- +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CA"] + }, + "destinations": { + "allowedPrefixes": ["+1"] + }, + "outboundPSTN": { + }, + "inboundPSTN": { + }, + "outboundSMS": { + }, + "inboundSMS": { + } + + } +} +---- + +**Link/Unlink a Profile to an Entity** + +To link a Profile to an Account + +.... +curl -X PUT -H "X-HTTP-Method-Override:LINK" -H "Link:;rel=related" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +To unlink a Profile from an Account + +.... +curl -X PUT -H "X-HTTP-Method-Override:UNLINK" -H "Link:;rel=related" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +To link a Profile to an Organization + +.... +curl -X PUT -H "X-HTTP-Method-Override:LINK" -H "Link:;rel=related" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +To unlink a Profile from an Organization + +.... +curl -X PUT -H "X-HTTP-Method-Override:UNLINK" -H "Link:;rel=related" https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2123 +.... + +[[Profiles_List]] +== Profile List Resource + +* Profile List Resource URI. */2012-04-24/Profiles* + +=== Supported Operations + +**HTTP GET**. Returns the list representation of all the *Profile* resources. + +The response will include a JSON document in the response body with this +format +.... +[{ + "uri": "http://127.0.0.1:8080/restcomm/2012-04-24/Profiles/PRae6e420f425248d6a26948c17a9e2acf", + "sid": "PRae6e420f425248d6a26948c17a9e2acf", + "dateUpdated": 1516745449949, + "dateCreated": 1516745449949 +}] +.... + +**HTTP POST**. +Creates a new Profile.The body of the request is expected to contain a JSON document compliant to the Profile +schema. + +==== Response Status +[cols=",",options="header",] +|============================================================================================== +|Status |Description +|201 Created | Profile created. Body contains Profile JSon document +|403 Forbidden |Only Super Admin is allowed to modify/create a Profile +|400 Bad Request | Body contains a Profile not compliant with schema +|============================================================================================== + +==== Response Headers +[cols=",",options="header",] +|============================================================================================== +|Header |Description +|Location | URL to new Profile created +|============================================================================================== diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/recordings-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/recordings-api.adoc new file mode 100644 index 0000000000..6ecdcbd96e --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/recordings-api.adoc @@ -0,0 +1,206 @@ += Restcomm API – Recordings + +[[Recordings]] +== Recordings + +Recordings are generated when you use the ** verb. Those recordings are hosted with RestComm for you to retrieve. The Recordings list resource represents the set of an account's recordings. + +=== Recording Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Recordings/\{RecordingSid}* + +To download the audio file just append *.wav* after the *RecordingSid.* + +=== Resource Properties + +[cols=",",options="header",] +|========================================================================== +|Property |Description +|Sid |A string that uniquely identifies this recording. +|DateCreated |The date that this recording was created. +|DateUpdated |The date that this recording was last updated. +|AccountSid |The unique id of the Account that created this recording. +|CallSid |The unique id of the call during which the recording was made. +|Duration |The length of the recording, in seconds. +|ApiVersion |The API version in use during the recording. +|Uri |The URI for this account, relative to https://localhost:restcomm. +|FileUri |The File URI for this recording, relative to https://localhost:restcomm. It can be used to access the WAV file +|S3Uri |The S3 URI for this recording - Exists ONLY IF Amazon S3 integration is enabled and security level is NONE- +|========================================================================== + +=== Supported Operations + +*HTTP GET.* Returns the representation of a Recording resource, including the properties above. +**HTTP DELETE**. Removes the recording from the account. + +== Recording List Resource + +=== Recording List Resource URI + +* */2012-04-24/Accounts/{AccountSid}/Recordings* + +* */2012-04-24/Accounts/{AccountSid}/Calls/{CallSid}/Recordings* + +NOTE: Unlike the Recording instance resource described above, the list of recordings IS protected by your account credentials like most parts of this API. You must use HTTP basic auth to access the Recordings list resource.* + +=== Supported Operations + +==== HTTP GET + +Returns the list representation of all the Recording resources for this Account, including the properties above. + +== How to Record a Message + +Go to the RCML section to learn how to record a message. + +== Get List of Recordings + +The list of recorded *wav* files can be found in the directory *$RESTCOMM_HOME/standalone/deployments/restcomm.war/recordings/* + +From the bash terminal, you can run the command below: + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json +.... + +The response will be similar to the one below. + +[source,decode:true] +---- +{"page":0,"num_pages":0,"page_size":50,"total":34,"start":"0","end":"34","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=0&PageSize=50","recordings": + [ + { + "sid":"RF50675909d9c94acda36f0e119b6cb431", + "date_created":"Mon, 6 Jan 2014 08:51:07 +0900", + "date_updated":"Mon, 6 Jan 2014 08:51:07 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CAfe9ce46f104f4beeb10c83a5ddd2be66", + "duration":"14.70275", + "api_version":"2012-04-24", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/RE50675909d9c94acda36f0e119b6cb431.json", + "file_uri":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav" + }, + ... + ] +} +---- + +NOTE: ** holds the file name of the recorded message. The recording Sid.**wav** is available in the file system only. + +If you want to return the recording url you will need to parse the */2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/REb4c03af76cdc4a27aad0d9d759e119bc* response from Restcomm and add the extension .**wav** + +The ** holds the http URI that can be used for playback or to download the recorded message. +Here is how to access the file using http *https://IP_ADDRESS/restcomm/recordings/REb4c03af76cdc4a27aad0d9d759e119bc.wav* +  + +== List Filter + +**HTTP GET**. The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================================== +|Parameter |Description +|StartTime |Only show recordings that started on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for recordings that started at or before midnight on a date, and StartTime=YYYY-MM-DD for recordings that started at or after midnight on a date. +|EndTime |Only show recordings that ended on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for recordings that started at or before midnight on a date, and StartTime=YYYY-MM-DD for recordings that started at or after midnight on a date. +|CallSid |Only show recordings that have been started from this CallSid +|=========================================================================================================================================================================================================================================================================== + +  + +=== Filter using the CallSid parameter. + +The example below will only return Recordings that has been started from this CallSid + +.... + curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?CallSid=CAfe9ce46f104f5beeb10c83a5dad2be66 +.... + +The result will be similar to the one below + +[source,lang:xml,decode:true] +---- +{"page":0,"num_pages":0,"page_size":50,"total":17,"start":"0","end":"17","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=0&PageSize=50","recordings": + [ + { + "sid":"RF50675909d9c94acda36f0e119b6cb431", + "date_created":"Mon, 6 Jan 2014 08:51:07 +0900", + "date_updated":"Mon, 6 Jan 2014 08:51:07 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CAfe9ce46f104f5beeb10c83a5dad2be66", + "duration":"14.70275", + "api_version":"2012-04-24", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/RE50675909d9c94acda36f0e119b6cb431.json", + "file_uri":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav" + }, + ... + ] +} +---- + +== Paging Information + +*HTTP GET.* The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|PParameter |Description +|Page |The current page number. Zero-indexed, so the first page is 0. +|NumPages |The total number of pages. +|PageSize |How many items are in each page +|Total |The total number of items in the list. +|Start |The position in the overall list of the first item in this page. +|End |The position in the overall list of the last item in this page. +|======================================================================= + +  + +=== Example. + +The command below will return a single item from the list of recordings using the PageSize parameter + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?PageSize=1 +.... + +The result of the *PageSize* parameter + +[source,lang:xml,decode:true] +---- +{"page":0,"num_pages":34,"page_size":1,"total":34,"start":"0","end":"0","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=0&PageSize=1","previous_page_uri":"null","next_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=1&PageSize=1&AfterSid=RF50675909d9c94acda36f0e119b6cb431","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings.json?Page=34&PageSize=1","recordings": + [ + { + "sid":"RF50675909d9c94acda36f0e119b6cb431", + "date_created":"Mon, 6 Jan 2014 08:51:07 +0900", + "date_updated":"Mon, 6 Jan 2014 08:51:07 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "call_sid":"CAfe9ce46f104f5beeb10c83a5dad2be66", + "duration":"14.70275", + "api_version":"2012-04-24", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/RE50675909d9c94acda36f0e119b6cb431.json", + "file_uri":"http://instance1.restcomm.com:8080/restcomm/recordings/RE50675909d9c94acda36f0e119b6cb431.wav" + } + ] +} +---- + +  + +== Additional Paging Information. + +The API returns URIs to the next, previous, first and last pages of the returned list as shown in the table below: + +=== Request Parameters + +[cols=",",options="header",] +|============================================================ +|Parameter |Description +|Uri |The URI of the current page. +|Firstpageuri |The URI for the first page of this list. +|Nextpageuri |The URI for the next page of this list. +|Previouspageuri |The URI for the previous page of this list. +|Lastpageuri |The URI for the last page of this list. +|============================================================ \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/sms-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/sms-api.adoc new file mode 100644 index 0000000000..7d2572fde4 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/sms-api.adoc @@ -0,0 +1,320 @@ += Restcomm API – SMS + +[[SMS]] +== SMS + +A *SMS Message* resource represents an inbound or outbound SMS message. + +=== SMS Message Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/SMS/Messages/\{SMSMessageSid}* + +==== Resource Properties + +[cols=",",options="header",] +|======================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this SMS Message. +|DateCreated |The date that this SMS Message was created. +|DateUpdated |The date that this SMS Message was last updated. +|DateSent |The date that the SMS was sent or received by RestComm. +|AccountSid |The unique id of the Account that sent or received this SMS message. +|From |The phone number or short code that initiated the message. +|To |The phone number or short code that received the message. +|Body |The text body of the SMS message. Up to 160 characters long. +|Status |The status of this SMS message. Possible values are queued, sending, sent, failed, and received. +|Direction |The direction of this SMS message. Possible values are incoming, outbound-api, outbound-call. +|ApiVersion |The API version RestComm used to handle the SMS message. +|Uri |The URI for this account, relative to https://localhost/restcomm. +|======================================================================================================== + +==== Supported Operations + +**HTTP GET**. Returns the representation of an SMS Message resource, including the properties above. SMS Message List Resource + +=== SMS Message List Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/SMS/Messages* + +==== Supported Operations + +===== HTTP GET + +Returns the list representation of all the Call resources for this Account, including the properties above.   + +===== HTTP POST + +Sends a new SMS Message and returns the representation of the SMS Message resource, including the properties above. Below you will find a list of required and optional parameters. + +====== Request Parameters + +Description A phone number that is enabled for SMS. The destination phone number in E.164 format. The text of the message you want to send, limited to 160 characters. + +Parameter + +From(Required) + +To(Required) + +Body(Required) + +== Using SMS and making DID calls + +You need to configure Restcomm to send SMS messages and DID phone calls to a Service Provider for provisioning. In the *restcomm.xml* file, the outbound-proxy-uri and the SMS outbound-endpoint must point to the Service Provider IP address. You may also decide to use Restcomm AMI. + +== Send SMS Messages + +Note the encoding used *%2B13216549878* instead of the **+13216549878**  The *+* sign is encoded to to send SMS from the command line. "**From**" DID number The "**From**" number should be the DID SMS enabled number from VoIP Innovations. From the bash terminal, you can run the command below: + +.... +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages -d "To=%2B13216549878" -d "From=%2B19876543212" -d "Body=This is a test from RestComm" +.... + +== Get list of SMS Messages + +This will display list of message sent + +From the bash terminal, you can run the command below: + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages +.... + +[[example-post-response---xml-and-json]] +== Example POST Response - XML and JSON + +=== XML POST Response + +---- +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e0f425248d6a26948c17a9e2acf/SMS/Messages -d "To=%2B1321654879" -d "From=%2B1654123987" -d "Body=This is a test from RestComm" +---- + + +---- + + + SM55ce5cf07b9649c283cbacab4dae56a9 + Thu, 19 Nov 2015 07:21:24 -0500 + Thu, 19 Nov 2015 07:21:24 -0500 + + ACae6e420f425248d6a26948c17a9e2acf + +1654123987 + +1321654879 + This is a test from RestComm + sending + outbound-api + 0 + USD + 2012-04-24 + /2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM55ce5cf07b9649c283cbacab4dae56a9 + +---- + +=== JSON POST Response + +---- +curl -X POST https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-20f425248d6a26948c17a9e2acf/SMS/Messages.json -d "To=%2B1321654879" -d "From=%2B1654123987" -d "Body=This is a test from RestComm" +---- + + +---- +{ + "sid": "SM5dd70f7ea54e47f1a49749debeec3f7f", + "date_created":"Thu, 19 Nov 2015 07:21:35 -0500", + "date_updated":"Thu, 19 Nov 2015 07:21:35 -0500", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "from":"+1654123987", + "to":"+1321654879", + "body":"This is a test from RestComm", + "status":"sending", + "direction":"outbound-api", + "price":"0", + "price_unit":"USD", + "api_version":"2012-04-24", + "uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM5dd70f7ea54e47f1a49749debeec3f7f.json" +} +---- + +[[example-get-response]] +== Example GET Response + +=== JSON GET Response + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json +---- + + +---- +{"page":0,"num_pages":0,"page_size":50,"total":34,"start":"0","end":"34","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=0&PageSize=50","messages": + [ + { + "sid":"SM55ce5cf07b9649c283cbacab4dae56a9", + "date_created":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_updated":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_sent":"2015-11-19T07:21:24.000-05:00", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "from":"+19876543212", + "to":"+13216549878", + "body":"This is a test from RestComm", + "status":"sent", + "direction":"outbound-api", + "price":"0", + "price_unit":"USD", + "api_version":"2012-04-24", + "uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM55ce5cf07b9649c283cbacab4dae56a9.json" + }, + ... + ] +} +---- + +[[get-response-using-sms-sid]] +== Get Response Using SMS SID + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e42f425248d6a26948c17a9e2acf/SMS/Messages/SM55ce5cf07b9649c283cbacab4dae56a9.json +---- + + +---- +{ + "sid":"SM55ce5cf07b9649c283cbacab4dae56a9", + "date_created":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_updated":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_sent":"2015-11-19T07:21:24.000-05:00", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "from":"+19876543212", + "to":"+13216549878", + "body":"This is a test from RestComm", + "status":"sent", + "direction":"outbound-api", + "price":"0", + "price_unit":"USD", + "api_version":"2012-04-24", + "uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM55ce5cf07b9649c283cbacab4dae56a9.json" +} +---- +  + +== List Filter + +**HTTP GET**. The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================================== +|Parameter |Description +|To |Only show messages to this phone number or Client identifier. +|From |Only show messages from this phone number or Client identifier. +|StartTime |Only show messages that started on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for messages that started at or before midnight on a date, and StartTime=YYYY-MM-DD for messages that started at or after midnight on a date. +|EndTime |Only show messages that ended on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for messages that started at or before midnight on a date, and StartTime=YYYY-MM-DD for messages that started at or after midnight on a date. +|Body |Only show messages that contain this body. +|=========================================================================================================================================================================================================================================================================== + +  + +=== Filter using the From parameter. + +The example below will only return Messages made from client Alice + +.... + curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?From=alice +.... + +The result will be similar to the one below + +[source,decode:true] +---- +{"page":0,"num_pages":0,"page_size":50,"total":1,"start":"0","end":"1","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=0&PageSize=50","messages": + [ + { + "sid":"SM55ce5cf07b9649c283cbacab4dae56a9", + "date_created":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_updated":"Thu, 19 Nov 2015 07:21:24 -0500", + "date_sent":"2015-11-19T07:21:24.000-05:00", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "from":"alice", + "to":"+13216549878", + "body":"This is a test from RestComm", + "status":"sent", + "direction":"outbound-api", + "price":"0", + "price_unit":"USD", + "api_version":"2012-04-24", + "uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM55ce5cf07b9649c283cbacab4dae56a9.json" + } + ] +} +---- + +== Paging Information + +*HTTP GET.* The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|Parameter |Description +|Page |The current page number. Zero-indexed, so the first page is 0. +|NumPages |The total number of pages. +|PageSize |How many items are in each page +|Total |The total number of items in the list. +|Start |The position in the overall list of the first item in this page. +|End |The position in the overall list of the last item in this page. +|======================================================================= + +  + +=== Example. + +The command below will return a single item from the list of messages using the PageSize parameter + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?PageSize=1 +.... + +The result of the *PageSize* parameter + +[source,decode:true] +---- +{"page":0,"num_pages":34,"page_size":1,"total":34,"start":"0","end":"0","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=0&PageSize=1","previous_page_uri":"null","next_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=1&PageSize=1&AfterSid=SM00ae962506694a61a4e29d776918a747","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages.json?Page=34&PageSize=1","messages": + [ + { + "sid":"SM00ae962506694a61a4e29d776918a747", + "date_created":"Fri, 5 Jul 2013 21:32:40 +0900", + "date_updated":"Fri, 5 Jul 2013 21:32:40 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "from":"19549376176", + "to":"+13213557674", + "body":"Hello", + "status":"received", + "direction":"inbound", + "price":"0.00", + "price_unit":"USD", + "api_version":"2012-04-24", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/SMS/Messages/SM00ae962506694a61a4e29d776918a747.json" + } + ] +} +---- + +  + +== Additional Paging Information. + +The API returns URIs to the next, previous, first and last pages of the returned list as shown in the table below: + +=== Request Parameters + +[cols=",",options="header",] +|============================================================ +|Parameter |Description +|Uri |The URI of the current page. +|Firstpageuri |The URI for the first page of this list. +|Nextpageuri |The URI for the next page of this list. +|Previouspageuri |The URI for the previous page of this list. +|Lastpageuri |The URI for the last page of this list. +|============================================================ \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/transcriptions-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/transcriptions-api.adoc new file mode 100644 index 0000000000..bb696bef37 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/transcriptions-api.adoc @@ -0,0 +1,193 @@ += Restcomm API – Transcriptions + +[[Transcriptions]] +== Transcriptions + +A Transcription resource represents a transcription of a recording. A transcription is a text version of a recording produced using automatic speech recognition. + +=== Transcription Resource + +==== Transcription Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Transcriptions/\{TranscriptionSid}* + +==== Resource Properties + +[cols=",",options="header",] +|====================================================================================================================== +|Property |Description +|Sid |A string that uniquely identifies this transcription. +|DateCreated |The date that this transcription was created. +|DateUpdated |The date that this transcription was last updated. +|AccountSid |The unique id of the Account that created this transcription. +|Status |A string representing the status of the transcription. Possible values are in-progress, completed, and failed. +|RecordingSid |The unique id of the Recording this Transcription was made of. +|Duration |The duration of the transcribed audio, in seconds. +|TranscriptionText |The text content of the transcription. +|Uri |The URI for this account, relative to https://localhost/restcomm. +|====================================================================================================================== + +==== Supported Operations + +**HTTP GET**. Returns the representation of a Transcription resource, including the properties above. + +**HTTP DELETE**. Removes the Transcription from the account. + +=== Transcription List Resource + +==== Transcription List Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/Transcriptions* + +==== Supported Operations + +**HTTP GET**. Returns the list representation of all the Transcription resources for this Account, including the properties above. + +== Get list of Transcriptions + +This will display list of transcription + +From the bash terminal, you can run the command below: + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json +.... + +The response will be similar to the one below. + +[source,lang:xml,decode:true] +---- +[ +{"page":0,"num_pages":0,"page_size":50,"total":34,"start":"0","end":"34","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=0&PageSize=50","transcriptions": + [ + { + "sid": "RF20000000000000000000000000000001", + "date_created":"Wed, 30 Oct 2013 16:28:33 +0900", + "date_updated":"Wed, 30 Oct 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "status":"completed", + "recording_sid":"CA5FB00000000000000000000000000002", + "duration":"14.70275", + "transcription_text":"Hello, Welcome to RestComm Connect", + "price":"0.0", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions/NOb88ccff6c9e04f989de9415a555ad84d.json.json" + }, + ... + ] +} +] +---- + +== List Filter + +**HTTP GET**. The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================================== +|Parameter |Description +|StartTime |Only show transcriptions that started on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for transcriptions that started at or before midnight on a date, and StartTime=YYYY-MM-DD for transcriptions that started at or after midnight on a date. +|EndTime |Only show transcriptions that ended on this date, given as YYYY-MM-DD. Also supports inequalities, such as StartTime=YYYY-MM-DD for transcriptions that started at or before midnight on a date, and StartTime=YYYY-MM-DD for transcriptions that started at or after midnight on a date. +|TranscriptionText |Only show transcriptions that contain this TranscriptionText +|=========================================================================================================================================================================================================================================================================== + +  + +=== Filter using the TranscriptionText parameter. + +The example below will only return Transcriptions that contain this TranscriptionText + +.... + curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?TranscriptionText=RestComm +.... + +The result will be similar to the one below + +[source,decode:true] +---- +{"page":0,"num_pages":0,"page_size":50,"total":13,"start":"0","end":"13","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=0&PageSize=50","previous_page_uri":"null","next_page_uri":"null","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=0&PageSize=50","transcriptions": + [ + { + "sid": "RF20000000000000000000000000000001", + "date_created":"Wed, 30 Oct 2013 16:28:33 +0900", + "date_updated":"Wed, 30 Oct 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "status":"completed", + "recording_sid":"CA5FB00000000000000000000000000002", + "duration":"14.70275", + "transcription_text":"Hello, Welcome to RestComm Connect", + "price":"0.0", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions/NOb88ccff6c9e04f989de9415a555ad84d.json.json" + }, + ... + ] +} +---- + +== Paging Information + +*HTTP GET.* The following GET query string parameters allow you to limit the list returned. Note, parameters are case-sensitive: + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|PParameter |Description +|Page |The current page number. Zero-indexed, so the first page is 0. +|NumPages |The total number of pages. +|PageSize |How many items are in each page +|Total |The total number of items in the list. +|Start |The position in the overall list of the first item in this page. +|End |The position in the overall list of the last item in this page. +|======================================================================= + +  + +=== Example. + +The command below will return a single item from the list of transcriptions using the PageSize parameter + +.... +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:77f8c12cc7b8f8423e5c38b035249166@127.0.0.1:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?PageSize=1 +.... + +The result of the *PageSize* parameter + +[source,lang:xml,decode:true] +---- +{"page":0,"num_pages":34,"page_size":1,"total":34,"start":"0","end":"0","uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json","first_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=0&PageSize=1","previous_page_uri":"null","next_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=1&PageSize=1&AfterSid=RF20000000000000000000000000000001","last_page_uri":"/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions.json?Page=34&PageSize=1","transcriptions": + [ + { + "sid": "RF20000000000000000000000000000001", + "date_created":"Wed, 30 Oct 2013 16:28:33 +0900", + "date_updated":"Wed, 30 Oct 2013 16:28:33 +0900", + "account_sid":"ACae6e420f425248d6a26948c17a9e2acf", + "status":"completed", + "recording_sid":"CA5FB00000000000000000000000000002", + "duration":"14.70275", + "transcription_text":"Hello, Welcome to RestComm Connect", + "price":"0.0", + "uri":"/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Transcriptions/NOb88ccff6c9e04f989de9415a555ad84d.json.json" + } + ] +} +---- + +  + +== Additional Paging Information. + +The API returns URIs to the next, previous, first and last pages of the returned list as shown in the table below: + +=== Request Parameters + +[cols=",",options="header",] +|============================================================ +|Parameter |Description +|Uri |The URI of the current page. +|Firstpageuri |The URI for the first page of this list. +|Nextpageuri |The URI for the next page of this list. +|Previouspageuri |The URI for the previous page of this list. +|Lastpageuri |The URI for the last page of this list. +|============================================================ \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/uml/incoming_number_logic.puml b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/uml/incoming_number_logic.puml new file mode 100644 index 0000000000..cb8adbdd98 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/uml/incoming_number_logic.puml @@ -0,0 +1,24 @@ +@startuml +start + + +:Retrieve Number from DB (In IncomingOrganization); + +if (Number Matched?) then (yes) + :Trigger linked Application; +else (no) + if (IncomingOrganization != null?) then (yes) + :Retrieve Regexes In IncomingOrganization; + :Sort Regexes by Length; + repeat + if (Number Matched?) then (yes) + :Trigger linked Application; + endif + repeat while (more regexes || !matched?) + else (no) + :No application found; + endif +endif + +stop +@enduml diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/usage-records-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/usage-records-api.adoc new file mode 100644 index 0000000000..c0905d7980 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/usage-records-api.adoc @@ -0,0 +1,206 @@ += Restcomm API – Usage Records + +[[usage-records]] +== Usage Records + +The UsageRecords REST resource provides a simple API to retrieve usage made by your Restcomm account during any time period and by any usage category. This makes it easy to build reporting and analytics tools for your application. UsageRecords used in combination with Subaccounts created for each of your end-users make it possible to build recurring usage-based billing systems on top of Restcomm's API with just a few simple API calls. + +You can also set up usage triggers to notify your application when a particular category of usage reaches a threshold on a daily, monthly, yearly, or all-time basis. Triggers can help determine if your users have reached a cap on usage, or if your application may have runaway requests. For more on usage triggers, see the Usage Triggers documentation. + +[[list]] +=== UsageRecords List Resource + +[[list-uri]] +==== Resource URI +*/2012-04-24/Accounts/{AccountSid}/Usage/Records* + +[[instance-properties]] +==== Resource Properties + +This resource and its subresources always return a list of UsageRecords. Each UsageRecord is represented by the following properties: + +[cols=",",options="header",] +|============================================================================================================================================================================================================================================================== +|Property |Description +|Category |The category of usage. See Usage Categories below. +|Description |A human-readable description of the usage category. +|AccountSid |The Account that accrued the usage. +|StartDate |The first date for which usage is included in this UsageRecord, formatted as YYYY-MM-DD. All dates are in GMT. +|EndDate |The last date for which usage is included in this UsageRecord, formatted as YYYY-MM-DD. All dates are in GMT. +|Usage |The amount of usage (e.g. the number of call minutes). This is frequently the same as `Count`, but may be different for certain usage categories like calls, where `Count` represents the number of calls and `Usage` represents the number of minutes. +|UsageUnit |The units in which `Usage` is measured. For example `minutes` for calls, `messages` for SMS. +|Count |The number of usage events (e.g. the number of calls). +|CountUnit |The units in which `Count` is measured. For example `calls` for calls, `messages` for SMS. +|Price |The total price of the usage, in the currency associated with the account. +|PriceUnit |The currency in which `Price` is measured, in ISO 4127 format (e.g. `usd`, `eur`, `jpy`). +|Uri |The URI that returns only this UsageRecord, relative to `https://Restcomm_IP_ADDRESS` +|SubresourceUris |Subresource Uris for this UsageRecord. See List Subresources. +|============================================================================================================================================================================================================================================================== + +[[usage-count-price]] +==== Usage, Count, and Price + +Each UsageRecord contains three amounts: `Usage`, `Count`, and `Price`. `Usage` is the primary way usage is measured for that category: `minutes` for calls, `messages` for SMS, etc. `Count` is the number of usage events: `calls` for calls, etc. And `Price` is the price of the usage in the currency associated with the account. Each UsageRecord also has fields that show the units in which each amount is measured: `Usage` is measured in units of `UsageUnit`, for instance. These fields make it easy to build usage dashboards. For example, you can always display human-readable strings describing usage with "`$Usagz` + +[[usage-categories]] +==== Usage Categories + +A UsageRecord's `Category` defines the type of usage it represents. The full list of all categories is link:#usage-all-categories[here], but you'll usually focus on just a few common categories: + +[cols=",",options="header",] +|================================================================================================================================================================================================================================================================================== +|             Category |Description +|calls |All voice calls. `Count` is the number of calls and `Usage` is the number of minutes. +|sms |All SMS messages. `Count` and `Usage` are both the number of messages sent. +|phonenumbers |All phone numbers owned by the account. +|recordings |Recordings of voice calls. `Count` is the number of recordings and `Usage` is the number of recorded minutes. Note that Restcomm doesn't charge for making recordings (only storing them long term) so `Price` will always be 0. +|transcriptions |Transcriptions of voice calls. `Count` is the number of transcriptions and `Usage` is the number of transcribed minutes. +|totalprice |Total price of all usage. `Usage` will be the same as `Price`, and `Count` will be empty. Note that because some Restcomm costs may not be included in any usage category, the sum of the `Price` of all UsageRecords may not be equal to the `Price` of `TotalPrice`. +|================================================================================================================================================================================================================================================================================== + +[[list-get]] +==== HTTP GET + +Returns *UsageRecords* for all usage categories. The list includes paging information. + +[[list-get-filters]] +===== List Filters + +By default, the UsageRecords resource will return one UsageRecord for each `Category`, representing all usage accrued all-time for the account. You can filter the usage `Category` or change the date-range over which usage is counted using optional GET query parameters. Note that query parameters are case-sensitive: + +[cols=",",options="header",] +|=========================================================================================================================================================================================================================================================== +|Parameter |Description +|Category |Only include usage of this usage category. +|StartDate |Only include usage that has occurred on or after this date. Format is YYYY-MM-DD. All dates are in GMT. As a convenience, you can also specify offsets to today. For example, `StartDate=-30days` will make `StartDate` be 30 days before today. +|EndDate |Only include usage that has occurred on or before this date. Format is YYYY-MM-DD. All dates are in GMT. As a convenience, you can also specify offsets to today. For example, `EndDate=+30days` will make `EndDate` be 30 days from today. +|=========================================================================================================================================================================================================================================================== + +For example, you might request all usage records for the month of April, 2012. In this case, the query string would be *`StartDate=2012-04-01&EndDate=2012-04-30`.* This would return one *UsageRecord* for each *usage-type* summarizing the usage during April. The list includes paging information. It's also possible to group usage by day, by month, or by year using the subresources described below. + +[[list-subresources]] +==== List Subresources + +The main UsageRecords list resource supports a variety of convenience subresources. In general these take the form: + +---- +/2010-04-01/Accounts/{AccountSid}/Usage/Records/{Subresource} +---- + +Supported subresources are: + +[cols=",",options="header",] +|================================================================================================================================================================= +|Subresource |Description +|Daily |Return multiple UsageRecords for each usage category, each representing usage over a daily time-interval. +|Monthly |Return multiple UsageRecords for each usage category, each representing usage over a monthly time-interval. +|Yearly |Return multple UsageRecords for each usage category, each representing usage over a yearly time-interval. +|AllTime |Return a single UsageRecord for each usage category, each representing usage over the date-range specified. This is the same as the root /Usage/Records. +|Today |Return a single UsageRecord per usage category, for today's usage only. +|Yesterday |Return a single UsageRecord per usage category, for yesterday's usage only. +|ThisMonth |Return a single UsageRecord per usage category, for this month's usage only. +|LastMonth |Return a single UsageRecord per usage category, for last month's usage only. +|================================================================================================================================================================= + +These convenience subresources can be used to draw a graph of daily calls, display dashboards of monthly usage across all usage categories, or build a simple usage-based billing system based on last month's usage totals. All subresources support the same list filters as the root UsageCounters resource. + +[[list-post]] +HTTP POST +++++++++ + +Not supported. + +[[list-put]] +HTTP PUT +++++++++ + +Not supported. + +[[list-delete]] +HTTP DELETE ++++++++++++ + +Not supported. + +[[usage-all-categories]] +==== Full List of All Usage Categories + +The full list of supported usage categories are: + +[cols=",",options="header",] +|========================================================================================================================================================================================================================================================================================= +|             Category |Description +|calls |All voice calls, inbound & outbound. `Count` is the number of calls and `Usage` is the number of minutes. +|calls-inbound |All inbound voice calls, to both toll-free and local numbers. +|calls-inbound-local |All inbound voice calls to local numbers. +|calls-inbound-tollfree |All inbound voice calls to toll-free numbers. +|calls-outbound |All outbound voice calls. +|calls-client |All Restcomm Client voice calls. +|calls-sip |All SIP calls. +|sms |All SMS messages, both inbound and outbound. `Count` and `Usage` are both the number of messages sent. +|sms-inbound |All inbound SMS messages, to both short-codes and long-codes. +|sms-inbound-shortcode |All inbound SMS messages to short-codes. +|sms-inbound-longcode |All inbound SMS messages to long-codes. +|sms-outbound |All outbound SMS messages, from both short-codes and long-codes. +|sms-outbound-shortcode |All outbound SMS messages from short-codes. +|sms-outbound-longcode |All outbound SMS messages from long-codes. +|phonenumbers |All phone numbers owned by the account, toll-free and local. +|phonenumbers-tollfree |All toll-free phone numbers owned by the account. +|phonenumbers-local |All local phone numbers owned by the account. +|shortcodes |All ShortCodes owned by the account, of all types. +|shortcodes-vanity |All vanity ShortCodes owned by the account. +|shortcodes-random |All randomly-assigned ShortCodes owned by the account. +|shortcodes-customerowned |All ShortCodes owned by the account that are leased from another provider. +|calleridlookups |CallerID (CallerName) lookups. +|recordings |Recordings of voice calls. `Count` is the number of recordings and `Usage` is the number of recorded minutes. Note that Restcomm doesn't charge for making recordings (only storing them long term) so `Price` will always be 0. +|transcriptions |Transcriptions of voice calls. `Count` is the number of transcriptions and `Usage` is the number of transcribed minutes. +|recordingstorage |Amount of storage used by call recordings stored for the account. `Count` is the number of stored recordings, `Usage` is the number of stored recorded minutes, and `Price` is the price of storing the recordings. +|totalprice |Total price of all usage. `Usage` will be the same as `Price`, and `Count` will be empty. Note that because some Restcomm costs may not be included in any usage category, the sum of the `Price` in all UsageRecords may or may not be equal to the `Price` of `TotalPrice`. +|========================================================================================================================================================================================================================================================================================= + +[[instance]] +=== UsageRecords Instance Resource + +You cannot make requests directly to a UsageRecord resource. Instead, make a request to the UsageRecords list resource or one of its + +[[example-of-getting-daily-calls-stats]] +== Example of Getting Daily Calls Stats + +---- +curl -X GET https://ACae6e420f425248d6a26948c17a9e2acf:PWD@127.0.0.1/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Usage/Records/Daily +---- + + +---- + + + + calls + Total Calls + ACae6e420f425248d6a26948c17a9e2acf + 2016-01-01 + 2016-01-01 + 4 + minutes + 2 + calls + 0.0 + USD + /todo + + + calls + Total Calls + ACae6e420f425248d6a26948c17a9e2acf + 2016-01-04 + 2016-01-04 + 0 + minutes + 1 + calls + 0.0 + USD + /todo + + +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/ussd-push-api.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/ussd-push-api.adoc new file mode 100644 index 0000000000..0b3243b44d --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/api/ussd-push-api.adoc @@ -0,0 +1,62 @@ += Restcomm API – USSD Push + +[[ussd-push]] +== UssdPush +A *UssdPush* resource represents a message sent from Restcomm-Connetc to a USSD Gateway. + +=== UssdPush Resource URI + +*/2012-04-24/Accounts/\{AccountSid}/UssdPush* + +=== Supported Operations + +*HTTP POST* sends a USSD message to the configured USSD Gateway + +== Example of UssdPush +The USSD Gateway to which Restcomm must send the USSD message must be configured in the restcomm.xml file. IP address and port must be configured (i.e. they are mandatory). Username/password for the USSD are optional. + +---- + + + IP_USSD_GW:PORT_NUMBER + + + +---- + +See below a general curl example for the USSD Push to the destination number 13019007654 (the MSISDN that will receive the USSD push session or notification according to YOUR_USSD_APP logic). + +---- +curl -X POST -H "application/json" https://ACae6e420f425248d6a26948c17a9e2acf:YOUR_PWD@RESTCOMM_IP_ADDRESS/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/UssdPush -d "From=Restcomm" -d "To=13019007654" -d "Url=https://RESTCOMM_IP_ADDRESS/restcomm-rvd/services/apps/YOUR_USSD_APP/controller" +---- + +For example, let's assume Restcomm-Connect runs over IP address 10.20.42.161 and HTTPS is disabled. So, assuming Restcomm-Connect HTTP default port is left to 8080, the following shows a curl example for a USSD Push session or notification sent to MSISDN 99077937, where YOUR_USSD_APP is an RVD project identified by AP8945ca7c0a534b1c8ec9c82b4e999a8c and YOUR_PWD equals the authorization token f8bc1274677b173d1a1cf3b9924eaa7e: + +---- +curl -X POST -H "application/json" http://ACae6e420f425248d6a26948c17a9e2acf:f8bc1274677b173d1a1cf3b9924eaa7e@10.20.42.161:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/UssdPush.json -d "From=myRestcommPushUssdApp" -d "To=99077937" -d "Url=http://10.20.42.161:8080/restcomm-rvd/services/apps/AP8945ca7c0a534b1c8ec9c82b4e999a8c/controller" +---- + +Note that the previous example differs from the general one not only by the fact that HTTP is used instead of HTTPS (then port is provided), but also by using json format. Then, a json answer like the following should be displayed (otherwise, an analogous XML answer would be displayed): + +---- +{ + "sid": "ID6f9befbbcbb4467d9e165353da159e70-CAe2d63be956d04c1ea86f8419a0212f14", + "InstanceId": "ID6f9befbbcbb4467d9e165353da159e70", + "date_created": "Mon, 25 Sep 2017 00:21:43 -0300", + "date_updated": "Mon, 25 Sep 2017 00:21:43 -0300", + "account_sid": "ACae6e420f425248d6a26948c17a9e2acf", + "to": "99077937", + "from": "USSD REST API", + "status": "QUEUED", + "price_unit": "USD", + "direction": "outbound-api", + "api_version": "2012-04-24", + "uri": "/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/ID6f9befbbcbb4467d9e165353da159e70-CAe2d63be956d04c1ea86f8419a0212f14.json", + "subresource_uris": { + "notifications": "/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/ID6f9befbbcbb4467d9e165353da159e70-CAe2d63be956d04c1ea86f8419a0212f14/Notifications.json", + "recordings": "/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/ID6f9befbbcbb4467d9e165353da159e70-CAe2d63be956d04c1ea86f8419a0212f14/Recordings.json" + } +} +---- + +Once the USSD Push session or notification is ended (by either the user or the application, status will transition from queued to completed. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part1.puml b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part1.puml new file mode 100644 index 0000000000..554192f06d --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part1.puml @@ -0,0 +1,46 @@ +@startuml +title __Record Verb - Part 1 (Start Recording)__ diagram - VoiceMail call flow (November 6, 2017) + +entity VoiceInterpreter +entity Call +entity MmsCallController +entity MgcpMediaGroup +entity IvrEndpoint +entity MediaGateway + +rnote over VoiceInterpreter + Single leg call, VoiceInterpreter + executes Record verb. +endnote + +VoiceInterpreter -> Call: Record +rnote over MmsCallController + onRecord() method +endnote +Call -> MmsCallController: Record +MmsCallController -> MgcpMediaGroup: Record +rnote over MgcpMediaGroup + **sender** is VoiceInterpreter + so when MgcpMediaGroup + will have to notify **originator** + VoiceInterpreter will get + the message +endnote +MgcpMediaGroup -> IvrEndpoint: PlayRecord +IvrEndpoint -> MediaGateway: RQNT AU/PR +MediaGateway -> IvrEndpoint: 200 Transaction Executed Normally + +create control Filesystem +MediaGateway -> Filesystem: write recording file + + +legend right + RQNT 4 mobicents/ivr/2@127.0.0.1:2427 MGCP 1.0 + N: restcomm@127.0.0.1:64915 + R: AU/oc(N),AU/of(N) + X: 0 + S: AU/pr(ip=beep.wav ri=file:RE237cc6a557d74f74950d4d89124d8350.wav cb=true prt=150 pst=150 rlt=500 eik=1234567890*# ) +endlegend + + +@enduml diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part2.puml b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part2.puml new file mode 100644 index 0000000000..64fe89ffd3 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/architecture_diagrams/Recording/Record_Verb/record_verb_part2.puml @@ -0,0 +1,66 @@ +@startuml + +actor Bob +entity VoiceInterpreter +entity Call +entity MmsCallController +entity MgcpMediaGroup +entity IvrEndpoint +entity MediaGateway + +Bob -> Call: BYE + +rnote over Call + Call actor will move + to StoppingRecord state +endnote + +Call -> MmsCallController: Stop +MmsCallController -> MgcpMediaGroup: Stop +MgcpMediaGroup -> IvrEndpoint: StopEndpoint +IvrEndpoint -> MediaGateway: RQNT AU/es(sg=pr) +create control Filesystem +MediaGateway -> Filesystem: move temp rec file to requested file +MediaGateway -> IvrEndpoint: 200 Transaction Executed Normally +MediaGateway -> IvrEndpoint: NTFY O:AU/oc AU/pr + +IvrEndpoint -> MgcpMediaGroup: IvrResponse +rnote over MgcpMediaGroup + When recording started, + originator (sender) + was set to VoiceInterpreter, + thus MgcpMediaGateway + will notifiy directly + VoiceInterpreter +endnote +MgcpMediaGroup -> VoiceInterpreter: MediaGatewayResponse + +rnote over VoiceInterpreter + VoiceInterpreter will + move to FinishRecording + state to create recording + entry in the DB and next + will either execute + Verb Action or will + ask for the next verb +endnote + +VoiceInterpreter -> Call: Hangup + +legend right +RQNT 147483675 mobicents/ivr/3@192.168.1.190 MGCP 1.0 +N:restcomm@192.168.1.190:2727 +X:5 +S:AU/es(sg=pr) +R:AU/oc(N),AU/of(N) + +--- + +NTFY 4 mobicents/ivr/6@192.168.1.190 MGCP 1.0 +O:AU/oc(AU/pr ri=file:RE808f6769f68648129b1a36c532d80675.wav na=1 vi=false rc=100) +X:8 +N:restcomm@192.168.1.190:2727 +endlegend + + +@enduml diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to build Restcomm-Connect from source.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to build Restcomm-Connect from source.adoc new file mode 100644 index 0000000000..aa49281a25 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to build Restcomm-Connect from source.adoc @@ -0,0 +1,108 @@ +[[build-from-source]] += How to build Restcomm-Connect from source + +== Requirements + +* You must have link:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git[git] installed on your computer +* You must have link:http://ant.apache.org/manual/install.html[ant] installed on your computer +* You must have link:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html[JDK - 7] installed on your computer +* You must be running link:https://maven.apache.org/download.cgi[maven] version 3.x.x on your computer + +== Obtaining git URL + +* Go to https://github.com/RestComm/Restcomm-Connect.git +You will see the page like this one below. Copy the URL in the *HTTPS* field. +The URL should look like this: https://github.com/RestComm/Restcomm-Connect.git + +image::images/1.png[] + +== Restcomm-Connect cloning + +In the bash window of your local computer create a directory where you should clone Restcomm-Connect: + +* run the command : + +[source,bash] +---- +git clone https://github.com/RestComm/Restcomm-Connect.git +---- +This command will create a new directory called RestComm-Connect. Go to this directory entering the command: + +[source,bash] +---- + cd Restcomm-Connect +---- + +The content of the directory should contain the following: + +image::images/6.png[] + +== Restcomm-Connect building + +* You will need to create a script to build Restcomm-Connect. +Copy the script below into a bash script on your local directory at the root of the RestComm-Connect. +In this tutorial, the script below is stored in the file *restcomm-connect-build.sh*. + +[source,bash] +---- +#!/bin/bash +export RESTCOMM_HOME=/home/yuliachornobrivets/Restcomm-Connect +export MAJOR_VERSION_NUMBER=7.6 +export BUILD_NUMBER=0 + +export WORKSPACE=$RESTCOMM_HOME +mkdir $WORKSPACE/dependencies +export DEPENDENCIES_HOME=$WORKSPACE/dependencies + + +ant release -f ./release/build.xml -Drestcomm.release.version=$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Drestcomm.branch.name=restcomm-release-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER -Dcheckout.restcomm.dir=$RESTCOMM_HOME -Dworkspace.restcomm.dir=$RESTCOMM_HOME/restcomm -Dcheckout.dir=$DEPENDENCIES_HOME +---- + +* Change the restcomm-connect-build.sh permission to make it executable as follows + +[source,bash] +---- +chmod +x ./restcomm-connect-build.sh +---- +The RestComm directory should now display the following content: + + +image::images/4.png[] + +* Before running the script, give enough system resources for MAVEN as follows: +[source,bash] +---- +export MAVEN_OPTS='-Xmx2048m -XX:MaxPermSize=1024m' +---- + +* Now, run the build script as follows: +[source,bash] +---- +./restcomm-connect-build.sh +---- + +This may take a while to build. If the build is successful, you should see this output at the end of the build: + +[source,bash] +---- +make-final-zip: + + [zip] Building zip: /home/username/Restcomm-Connect/release/Restcomm-JBoss-AS7-7.6.0.zip + +release: + +BUILD SUCCESSFUL +Total time: 42 minutes 11 seconds +---- +* At the root of the RestComm directory you should see: + + +image::images/2.png[] +* Go to the *release* directory. You will see the following files: + +image::images/3.png[] + +Note that the zip file called *Restcomm-JBoss-AS7-7.6.2* is the binary for JBoss container. +You can copy this zip file into a directory on your computer and unzip the content. + +Here you can read the detailed information on <>. 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 new file mode 100644 index 0000000000..ff9b867294 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to get started with Restcomm-Connect and Mysql.adoc @@ -0,0 +1,198 @@ +[[restcomm-connect-mysql]] += How to get started with Restcomm-Connect and Mysql + +_When working with the binary version of Restcomm, the default database is hsqlDB. +This is of course not suitable for production but it is provided as a way for you +to conveniently and quickly start up Restcomm. +For those who would like to run Restcomm on a local server or on another cloud based system, +the following tutorial will show how to get started with Restcomm and Mysql._ + +== Requirements + +* Install Restcomm using our <>. +* Install link:http://dev.mysql.com/doc/refman/5.7/en/installing.html[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/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] +---- + + + + + + + + + + + +---- + +== Step 2 : Configure the standalone-sip.xml to use the Mysql Connector +* Edit the file $RESTCOMM_HOME/standalone/configuration/standalone-sip.xml +* Edit the datasource and make sure it looks like the section below +* Note that the IP *192.168.1:3306* is the IP where mysql is listening for traffic + + +[source,bash] +---- + + + jdbc:mysql://192.168.1.3:3306/restcomm + mysqlDriver + TRANSACTION_READ_COMMITTED + + 100 + 200 + + + root + YourMysqlDBPwd + + + 100 + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 + h2 + + sa + sa + + + + + com.mysql.jdbc.Driver + + + org.h2.jdbcx.JdbcDataSource + + + +---- + +== Step 3 : Create restcomm database in mysql and grant DB privileges +* Create restcomm database in mysql as follows + +[source,bash] +---- + mysql -u root -p < $RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/scripts/mariadb/init.sql +---- +* The command above will create a restcomm database inside mysql +* log into mysql to make sure the database is created. +[source,bash] +---- +mysql -u root -p + +show databases; +use restcomm; +show tables; + +---- +* Grant the appropriate DB privileges to the user, in the example, root +[source,bash] +---- +GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.%' IDENTIFIED BY 'YourMysqlDBPwd' WITH GRANT OPTION; + +then save the changes as follows +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 + +WARNING: If you need to change an existing GRANT, you can use the ALTER command as follows + +ALTER USER PRIVILEGES ON *.* TO 'root'@'192.168.1.%' IDENTIFIED BY 'YourMysqlDBPwd' WITH GRANT OPTION; +---- +* Restart mysql service +[source,bash] +---- +sudo service mysql restart + +or like this + +sudo /etc/init.d/mysql restart +---- +WARNING: If you are unable to access your mysql server on the IP on which Restcomm is installed, please make sure you checking the following. +[source,bash] +---- +Edit the file /etc/mysql/my.cnf and make sure bind to 127.0.0.1 is disabled or commented out like this +#bind-address = 127.0.0.1 + +Run the following command to make sure mysql is not bound to the loopback (127.0.0.1) address (below it is listening to all IP) + +netstat -lnp | grep mysql +tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 7657/mysqld +unix 2 [ ACC ] STREAM LISTENING 77682 7657/mysqld /var/run/mysqld/mysqld.sock +---- + +== Step 4 : UPdate mybatis.xml file to use Mysql + +* Edit *$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/conf/mybatis.xml* +* The environment tag should look like the example below: +[source,bash] +---- + + + + + + + + + + +---- + +== Step 5 - Update the dao-manager in the dao-manager.xml file +* It should disable the default hsql and use mariadb sql which is the same as the one for mariadb +[source,bash] +---- + + + + ${restcomm:home}/WEB-INF/conf/mybatis.xml + + ${restcomm:home}/WEB-INF/scripts/mariadb/sql + + +---- + + + + +== Start Restcomm +* Go to the $RESTCOMM_HOME/bin/restcomm/ directory. + command: + +[source,bash] +---- +./start-restcomm.sh +---- + +* Open your web browser and go to the url – http://IP:8080. Instead of "IP" you should put your IP. + +* Log in with the administrator@company.com username and the RestComm password. Then you should change the default password. +If you have changed the default password before, you should insert your own password at once. + +Here you can read the detailed information on <>. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to use Mysql schema upgrade scripts.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to use Mysql schema upgrade scripts.adoc new file mode 100644 index 0000000000..d8f2bc30de --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to use Mysql schema upgrade scripts.adoc @@ -0,0 +1,56 @@ +[[mysql-schema-upgrade]] +*How to use Mysql schema upgrade scripts* + +*Overview* + +The Mysql schema upgrade scripts will take care to upgrade the schema of existing +Restcomm Mysql database to the latest schema. + +Before anything, scripts will create a backup of the existing database that will include schema and data. +Database backup files are located at: **$RESTCOMM_HOME/bin/restcomm/upgrade_scripts/backups** + +*Requirements* + +* Install mysql-clients package + +*Step 1 – Edit uprgade.conf* + +Edit and save the **$RESTCOMM_HOME/bin/restcomm/upgrade.conf** and provide the following: + +- MySQL server ip address +- MySQL server port +- MySQL username +- MySQL password +- Restcomm DB name + +*Step2 - Run the upgrade.sh script* + +Run the **$RESTCOMM_HOME/bin/restcomm/upgrade.sh** script. + +The script will first create backup of the existing database and then will proceed to apply the sql upgrade scripts. + +At the end the script will report the result like: + +``` ++---------+------------------------------------------------------+---------------------+---------+ +| Version | Description | Installed on | State | ++---------+------------------------------------------------------+---------------------+---------+ +| 1 | << Flyway Baseline >> | 2016-05-12 18:25:31 | Baselin | +| 7.5.1 | For 750 update instance id | 2016-05-12 18:25:32 | Success | +| 7.5.2 | For 750 update restcomm incoming phone numbers table | 2016-05-12 18:25:33 | Success | +| 7.5.3 | For 750 add instanceId to call details record table | 2016-05-12 18:25:33 | Success | +| 7.5.4 | For 750 add instanceid to registrations | 2016-05-12 18:25:33 | Success | +| 7.5.5 | For 750 update restcomm sms messages table | 2016-05-12 18:25:33 | Success | +| 7.5.6 | For 750 update restcomm application records | 2016-05-12 18:25:34 | Success | ++---------+------------------------------------------------------+---------------------+---------+ +``` + +*Troubleshooting* + +You can run the following script to check the status of the migration: + +**$RESTCOMM_HOME/bin/restcomm/db_migration_status.sh** + +If you need to restore a backup run the following backup: + +mysql -u MYSQL_USER -pMYSQL_PASSWORD -h MYSQL_HOST -P MYSQL_PORT < RESTCOMM_BACKUP_FILE diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVD Workspace Upgrade.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVD Workspace Upgrade.adoc new file mode 100644 index 0000000000..b3a1fc3ad5 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVD Workspace Upgrade.adoc @@ -0,0 +1,141 @@ +Given the new http://docs.telestax.com/restcomm-api-applications/[Applications REST API] available since the previous RestComm release (7.4.0), some modifications were done to better integrate RVD Projects with Application entities. So the native application server RVD will continue providing the RCML requested by RestComm's interpreters, but now using the Application entities. The list below contains a description of the main modifications: + +1. **RVD Workspace Migration**: RestComm bootstrap updates RVD workspace naming convention, Applications, IncomingPhoneNumbers and Clients; +2. **Integration of Applications with other entities**: AdminUI allows to set both Applications or URLs to RestComm Numbers or Clients; +3. **User Interface and internal modifications**: AdminUI and RVD UI obtain now the list of available applications using http://docs.telestax.com/restcomm-api-applications/[Applications REST API]. + +The following parts of this document are organised by following the 3 items mentioned above. + +[[rvd-workspace-migration]] +1. RVD Workspace Migration +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The migration executed on RestComm's bootstrap is a sequence of steps executed to adapt the filesystem and database with the new structure. The steps executed by the migration algorithm are: + +1. Backup RVD Workspace directory + +IMPORTANT: To backup database structures execute link:./RVDWorkspaceMigrationBackup.sql_.txt[this script.]) + +2. Synchronize RVD Project with Applications API (create the Application or update the existing one); +3. Rename the directory of the project inside RVD Workspace using the application SID obtained from step 2; +4. Update IncomingPhoneNumbers replacing the voice, SMS and USSD URLs that points to the application by its respective application SID; +5. Update Clients replacing the voice URL that points to the application by its respective application SID; +6. If the current project is the last one, store the result of the migration and continue with RestComm bootstrap, otherwise, get next RVD project and go to step 2. + +[[configuration]] +1.1 Configuration +^^^^^^^^^^^^^^^^^ + +The configuration required to run the migration algorithm on RestComm's bootstrap is placed inside $RESTCOMM_HOME/standalone/deploy/restcomm.war/WEB-INF/conf/restcomm.xml. The parameters to be configured inside this file are "**rvd-workspace-migration-enabled**" and "**default-email-address**", as described below: + +[cols=",,",] +|================================================================================================================================================================================== +|Parameter |Value |Description +|rvd-workspace-migration-enabled |**true** or *false* |Controls if the migration needs to be executed at RestComm's bootstrap. +|smtp-notify/host |DNS or IP address |Host address of the SMTP server. +|smtp-notify/user |string |The username with the SMTP server. +|smtp-notify/password |string |The password for the provided account with the SMTP server. +|smtp-notify/port |number |Port to be used with the SMTP server. +|smtp-notify/default-email-address |A valid email address using the format defined as addr-spec of RFC-2822 |Email that will receive the result of the migration after it finishes. +|================================================================================================================================================================================== + +[[execution]] +1.2 Execution +^^^^^^^^^^^^^ + +The default value of the parameter "**rvd-workspace-migration-enabled**" is "**true**" for the release that introduced this feature, and should be "**false**" for the next ones. + +After the execution of the migration, a file named "**.version**" will be created inside RVD's workspace directory storing the result of the migration and the version of RestComm that managed its execution. The following box represent the content of this file: + +[source,lang:default,decode:true] +---- +{"status":true,"version":"7.6.0"} +---- + +Once this file is present inside RVD's workspace and holds the current version of RestComm, the migration will not be executed in the next bootstrap of this version, even if the parameter "**rvd-workspace-migration-enabled**" still configured with the value "**true**". This strategy was created to allow only one automatic attempt of migration per RestComm version. + +If the migration failed and it's necessary to run another attempt, make sure to remove the file "**.version**" from RVD workspace and keep the value of the parameter "**rvd-workspace-migration-enabled**" as "**true**", and then restart RestComm. For more information see the **Troubleshooting** at session **1.4** of this document. + +[[logs]] +1.3 Logs +^^^^^^^^ + +During the execution of the process, RestComm will use 4 different resources to store the progress of the migration: specific log file, generic log file, RestComm Notifications and e-mail messages. + +The following table shows detailed information about each log resource. + +[cols=",,",] +|========================================================================================================================================================================================== +|Name |Description |Location +|workspace-migration.log |Specific log file used to store the full progress of migration, including error messages, stacktraces and more. |$RESTCOMM_HOME +|server.log |Generic log file used to display status messages with the result of the migration and/or important error messages. |$RESTCOMM_HOME/standalone/log +|RestComm Notification |Notification stored in the database to keep the history of beginning/end of the migration and also errors. |Menu "Logs > Notifications" at RestComm's Admin UI page +|e-mail message |Message sent to the address configured at the parameter "default-email-address" at the end of the migration with the results. |n/a +|========================================================================================================================================================================================== + +[[troubleshooting]] +1.4 Troubleshooting +^^^^^^^^^^^^^^^^^^^ + +While the migration is executed, some errors can be easily predicted/handled, but another ones require manual intervention due to the diversity of operations executed by the algorithm. + +Given that, it's important to emphasise that the migration needs to be executed with success, indifferent of the number of attempts. This process is required for several new features implemented across the platform. + +To help with manual troubleshooting of possible issues, a set of error codes was created describing each situation with is consequences and how to work around it. If some error occur, it can just skip the project that raised the problem or abort the migration, always storing details inside the log files. + +The following table have details about troubleshooting to each error code, also guiding which situation is recommended to execute the algorithm again. + +[cols=",,",] +|========================================================================================================================================================================================================================================================================================================================== +|Code |Comments |New attempt recommended? +|1 |The file system can be inaccessible or with insufficient permission to read. Check the workspace location and the permissions assigned to the directory before a new attempt. |Yes +|2 |One of the final steps executed failed. Since this is a generic error, the analysis need to consider if there is another error associated to this one, like error 12. In this case, see the description of the specific error. |n/a +|3 |The file system can be inaccessible or with insufficient permission to write. Check $RESTCOMM_HOME permissions before a new attempt. This error does not compromise the success of the migration and a new attempt is not required if this is the only error. |No +|4 |It was not possible to send the email at the end of the execution. Check the required configurations at the section 1.1 of this document and network connectivity. This error does not compromise the success of the migration and a new attempt is not required if this is the only error. |No +|5 |The file system can be inaccessible or with insufficient permission to write. Check the workspace location and the permissions assigned to this directory and also subdirectories before a new attempt. |Yes +|6 |The file system can be inaccessible or with insufficient permission to read or the state file is corrupted. Check the project location, the permissions assigned to this directory and subdirectories and also if the state file is consistent, before a new attempt. |Yes +|7 |To execute the synchronization of a project, RestComm uses the database creating or updating Application entities. Check if the database service is online and available to use. |Yes +|8 |Potential problem while communicating with database. Check if the database service is online and available to use. |Yes +|9 |Potential problem while communicating with database. Check if the database service is online and available to use. |Yes +|10 |Potential problem while communicating with database. Check if the database service is online and available to use. |Yes +|11 |Potential problem while communicating with database. Check if the database service is online and available to use. |Yes +|12 |The file system can be inaccessible or with insufficient permission to write. Check $RESTCOMM_HOME permissions before a new attempt. This error implies that was not be possible to store the result of the migration inside RVD's workspace, so a new attempt of execution is encouraged to keep data integrity. |Yes +|13 |The file system can be inaccessible, with insufficient permission to write or without enough space to make a copy of the workspace. Check workspace location, permissions and available free space in the partition before a new attempt. |Yes +|14 |Multiple applications are using the same FriendlyName for a project that has not been upgraded. One of them is probably already linked to the project. The rest will need to be taken care of manually. |No +|========================================================================================================================================================================================================================================================================================================================== + +Based on the table above, if a new attempt of execution is recommended, follow the steps below: + +1. Stop RestComm; +2. Make sure the parameter "**rvd-workspace-migration-enabled**" remains with the value "**true**" inside the configuration file "**restcomm.xml**"; +3. Remove the file "**.version**" inside RVD workspace directory; +4. Double check the recommendations provided by the column "Comments" in the previous table; +5. Start RestComm. + +To get more information about the configuration and execution of the algorithm, please make sure to read sections 1.1 and 1.2 of this document. + +IMPORTANT: In a new attempt of execution, the projects that were successfully migrated will be skipped to keep it consistent. + +If a manual intervention is required with the database, check REST API documentation for http://docs.telestax.com/restcomm-api-applications/[Applications], http://docs.telestax.com/restcomm-api-incomingphonenumbers/[IncomingPhoneNumbers] and http://docs.telestax.com/restcomm-api-clients/[Clients]. + +[[integration-of-applications-with-other-entities]] +2. Integration of Applications with other entities +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With the consistency provided by the efforts to improve the way we use Application entities, AdminUI was adapted to manage IncomingPhoneNumbers and Clients configuration with both URL or Applications in a more elegant way. + +By selecting the option **URL** in the first dropdown menu, the text field in the right will allow to inform an external provider for the RCML and also the HTTP method to be used. image:./images/Screen-Shot-2016-02-04-at-14.14.27.png[Screen Shot 2016-02-04 at 14.14.27,width=675,height=45] + +If the option **Application** is selected, use the button in the right side to browse Applications inside RectComm database and assign them to this IncomingPhoneNumber/Client. + +image:./images/Screen-Shot-2016-02-04-at-14.14.45.png[Screen Shot 2016-02-04 at 14.14.45,width=679,height=43] + +[[user-interface-internal-modifications]] +3. User Interface internal modifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some minor and abstract changes were made to better fit the list of Applications inside AdminUI and RVD UI. + +Before the modification, RVD was the provider of the list of available Projects to AdminUI and RVD UI, but now both UIs are using Applications REST API to get the complete list of applications from RestComm. + +This modification allows us to use a RestComm Applications created using a application server different than RVD in a transparent way to the final user, bringing more flexibility to RestComm. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVDWorkspaceMigrationBackup.sql_.txt b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVDWorkspaceMigrationBackup.sql_.txt new file mode 100644 index 0000000000..a8daf08cea --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/RVDWorkspaceMigrationBackup.sql_.txt @@ -0,0 +1,20 @@ +#SQL Script for MySQL/MariaDB to update DB with the schema changes for issue #530 +#Date: Dec 14 +#Author: Guilherme Humberto Jansen + +#To run the script use mysql client: +#mysql -u yourusername -p yourpassword yourdatabase < sql_update_script.sql + +USE restcomm; + +-- backup applications +CREATE TABLE restcomm_applications_migrationbkp LIKE restcomm_applications; +INSERT restcomm_applications_migrationbkp SELECT * FROM restcomm_applications; + +-- backup incoming phone numbers +CREATE TABLE restcomm_incoming_phone_numbers_migrationbkp LIKE restcomm_incoming_phone_numbers; +INSERT restcomm_incoming_phone_numbers_migrationbkp SELECT * FROM restcomm_incoming_phone_numbers; + +-- backup clients +CREATE TABLE restcomm_clients_migrationbkp LIKE restcomm_clients; +INSERT restcomm_clients_migrationbkp SELECT * FROM restcomm_clients; \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Automatic DID Provisioning.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Automatic DID Provisioning.adoc new file mode 100644 index 0000000000..3b83758ce5 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Automatic DID Provisioning.adoc @@ -0,0 +1,84 @@ +Restcomm Connect allows you to provision DID numbers easily from Voip Innovations through the Restcomm Admin Management Interface. This tutorial will show you how to attach a DID number to an application created using Restcomm Visual Designer.   + += Requirements + +* Restcomm AMI or Binary (version 7.1.5 and above) +* Voip Innovations API account and endpoint number +* VoiceRSS for Text to Speech API account + += Step 1 + +You must configure Restcomm for Text to Speech and for Voip Innovations. + +Open to *$RESTCOMM_HOME//standalone/deployments/restcomm.war/WEB-INF/conf/restcomm.xml* + +Modify the following lines + +* *Text to Speech with VoiceRSS* - enter your VoiceRSS API key + +[source,lang:default,decode:true] +---- +http://api.voicerss.org + Your_VoiceRSS_API_KEY +---- + +* *Voip Innovations API* + +[source,lang:default,decode:true] +---- + + YOUR_LOGIN_NAME + YOUR_LOGIN_PASSWORD + YOUR_ENDPOINT_NUMBER + https://backoffice.voipinnovations.com/api2.pl + +---- + +Then Start Restcomm + += Step 2 + +We are going to create a test application from the Restcomm Visual Designer (RVD) + +* Open you web browser and go to *http://127.0.0.1:8080/restcomm-rvd* +* Click on the Voice button +* Create a new Project called DIDTest +* In the Say verb text area, modify the text to something similar to the screen below. +* Press the *Save* button + +image:./images/restcomm-VI-DID-1.png[restcomm-VI-DID-1,width=740,height=271] + += Step 3 + +You must now attach a Voip Innovation DID number to the DIDTest application you created using the RVD + +* Open you web browser and go to http://127.0.0.1:8080/ +* Login to the Management Interface, in the Dashboard page, click on the menu Number +* Click on the +Register Number button + +In the Register Number window, + +* Click on the *Area Code* drop down list to select an area code. In this tutorial the area code selected is *501* + +* Press the *search* button to find all available DID numbers from that area code. + +image:./images/restcomm-VI-DID-2.png[restcomm-VI-DID-2,width=482,height=341] + +You will see a screenshot similar to the list below showing available DIDs from Voip Innovations. + +* Select the phone number you will like to attach to your DIDTest application. + +image:./images/restcomm-VI-DID-3.png[restcomm-VI-DID-3,width=449,height=337] + +* Click on the Optional Parameters button to reveal more configuration options +* Under Voice -> Voice Request URL, click on the options button to reveal a list of available applications +* Choose DIDTest and press the Register button to attach the DID number to your DIDTest application + +image:./images/restcomm-VI-DID-4.png[restcomm-VI-DID-4,width=486,height=461] + +The DID will now appear in the list of available numbers. + +[[warning]] += Warning + +This configuration doesn't take into firewall and NAT issues that you might need to configure in order to make an inward call into your local Restcomm instance running on a private IP address.         diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Configure and Connect to External DID Providers.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Configure and Connect to External DID Providers.adoc new file mode 100644 index 0000000000..4942136278 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Configure and Connect to External DID Providers.adoc @@ -0,0 +1,137 @@ +This tutorial will give you a short overview of what you need to do to connect Restcomm Cloud communication platform to following DID providers: + +* *VoipInnovations* +* *Bandwidth * +* *Nexmo* +* *Voxbone* + +[[requirements]] += Requirements + +* Basic Knowledge of Restcomm +* Account from any of the above mentioned DID providers +* <> +* Change Default Password as explained http://docs.telestax.com/restcomm-change-default-password/[HERE] + +[[step-1---configure-the-restcomm.conf-file]] += Step 1 - Configure the restcomm.conf file + +* Go to *$RESTCOMM_HOME/bin/restcomm* +* open the file *restcomm.conf* for edit + +To fill out the section *# Network configuration* run the following command on your bash terminal + +[source,lang:default,decode:true] +---- +$> ifconfig +enp19s0: flags=4163 mtu 1500 + inet 192.168.1.3 netmask 255.255.255.0 broadcast 192.168.1.255 + inet6 fe80::f2bf:97ff:fe03:9e0a prefixlen 64 scopeid 0x20 + ether f0:bf:97:03:9e:0a txqueuelen 1000 (Ethernet) + RX packets 44916 bytes 36481273 (34.7 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 37502 bytes 5636746 (5.3 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +$> netstat -r +Kernel IP routing table +Destination Gateway Genmask Flags MSS Window irtt Iface +default 192.168.1.1 0.0.0.0 UG 0 0 0 enp19s0 +192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 enp19s0 +---- + +Use the information above to fill out your configuration as shown in the example below: + +[source,lang:default,decode:true] +---- +NET_INTERFACE=enp19s0 +PRIVATE_IP=192.168.1.3 +SUBNET_MASK=255.255.255.0 +NETWORK=192.168.1.0 +BROADCAST_ADDRESS=192.168.1.255 +---- + +NOTE: If you want to be able to call your Restcomm instance by initiating a call from the internet, you will need to configure your firewall NAT and the ports defined below + +[[restcomm-ports-to-open-on-the-firewall-for-nat]] +== Restcomm Ports to open on the firewall for NAT + +* tcp:8080 +* udp:5080 +* udp:64535-65535 +* tcp/udp: 5060 + + +1. Port 8080 is used for the restcomm-management console over http +2. Port 5080 is used to make calls ex. sip:1234@Restcomm_IP:5080 +3. Port 64535-65535 are used for media RTP traffic +4. Port 5060 is used for SIP + +[[step-2---setting-the-static-public-ip-adress]] += Step 2 - Setting the Static Public IP Adress + +* Go to the file *restcomm.conf* under the section # PUBLIC IP ADDRESS +* Get the public IP address of the server on which Restcomm is installed + +''''' + +*Open your internet browser and in google.com, type, "what is my ip". This will give you the Public IP address of your Internet Facing Server* + +''''' + +Use the public IP address to fill out the STATIC_ADDRESS below +[source,lang:default,decode:true] +---- +# PUBLIC IP ADDRESS +STATIC_ADDRESS=SERVER_PUBLIC_IP_ADDRESS + +ex. STATIC_ADDRESS=222.222.111.111 +---- + +[[step-3---did-provider-configuration]] += Step 3 - DID Provider Configuration + +In the file **restcomm.conf**, go to the section + +---- +# DID Provision provider variable declarations +PROVISION_PROVIDER='NX' # values: VI (VoipInnovation), BW (Bandwidth), NX (Nexmo), VB (Voxbone) +#Username and password for all supported DID provision providers +DID_LOGIN=' ' +DID_PASSWORD=' ' +# VoipInnovation Endpoint ID +DID_ENDPOINT='' +#Bandwidth SiteId and AccountId +DID_SITEID='' +DID_ACCOUNTID=''   +---- + +Enter your account details as provided by your Telco Service Provider. + +''''' + +[[example-nexmo]] +== Nexmo Example + + if you were to use Nexmo, the configuration will be as follows: + +The DID_LOGIN will be your Nexmo API *key* and the DID_PASSWORD will be your Nexmo API *secret.* The leave the rest of the configuration as default + +---- +PROVISION_PROVIDER='NX' +DID_LOGIN='XXXX' +DID_PASSWORD='XXXX' +---- + +''''' + +* Save the restcomm.conf file +* start restcomm by running the script $RESTCOMM_HOME/bin/restcomm**/start-restcomm.sh** + +''''' + +You must stop ($RESTCOMM_HOME/bin/restcomm**/stop-restcomm.sh**) and start ($RESTCOMM_HOME/bin/restcomm**/start-restcomm.sh** )restcomm after making changes to the restcomm.conf file. + +''''' + +  diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting SMPP Endpoint through Nexmo.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting SMPP Endpoint through Nexmo.adoc new file mode 100644 index 0000000000..f7af37a4de --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting SMPP Endpoint through Nexmo.adoc @@ -0,0 +1,93 @@ +Restcomm comes with SMPP integration that allows sending messages from multiple SMPP endpoints. This tutorial will explain how to connect Restcomm SMPP to Nexmo. You can also connect Restcomm to any SMPP endpoint, for example, by using the Telscale SMSC gateway. + +[[requirements]] +Requirements +~~~~~~~~~~~~ + +* Latest version of Restcomm +* Nexmo Account + +[[step-1---get-nexmo-account-details]] +Step 1 - Get Nexmo Account Details +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Go into your Nexmo account dashboard and get the following data + +* In the screenshot below, you need the +* *Callback System-type* = text + +image:./images/restcomm-smpp-nexmo.jpg[restcomm-smpp-nexmo,width=478,height=248] + +You also need the API Settings + +* *Key :* +* *Secret :* + +image:./images/restcomm-smpp-nexmo2.jpg[restcomm-smpp-nexmo2,width=699,height=172] + +You also need to get the Nexmo gateway and the port as explained link:https://help.nexmo.com/hc/en-us/articles/204015743-Which-host-and-port-do-I-use-to-connect-to-Nexmo-SMPP-server-[HERE]   + +[[step-2---configure-restcomm-to-use-smpp]] +Step 2 - Configure Restcomm to Use SMPP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Edit the file  $RESTCOMM_HOME/bin/restcomm/smpp.conf You must set the SMPP_ACTIVATE variable to true for SMPP to be activated + +[source,lang:default,decode:true] +---- +# Connection details for SMPP Restcomm integration +SMPP_ACTIVATE='true' #default SMPP activate is always false. Set to true to activate SMPP +SMPP_SYSTEM_ID='xxxxxx' +SMPP_PASSWORD='xxxxxxx' +SMPP_SYSTEM_TYPE='xxxxxxx' #This is required when working with Nexmo for inbound SMS +SMPP_PEER_IP='xxxxxxxx' #use IP or DNS name of peer SMPP server +SMPP_PEER_PORT='xxxxx' +---- + +[[step-3---configure-restcomm-ip-and-required-features]] +Step 3 - Configure Restcomm IP and Required Features +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The next step is to configure the IP address and other features required to start Restcomm as explained <>. + +If SMPP is correctly started, you should see an output similar to the one below in the console. + +[source,lang:default,decode:true] +---- +08:19:22,697 INFO [org.restcomm.connect.smpp.SmppClientOpsThread] (Thread-602) SmppClientOpsThread started. +08:19:22,697 INFO [org.restcomm.connect.smpp.SmppService] (RestComm-akka.actor.default-dispatcher-6) SMPP Service started +08:19:22,796 INFO [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management +08:19:22,797 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990 +08:19:22,797 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.2.0.Final "Janus" started in 10923ms - Started 477 of 557 services (79 services are passive or on-demand) +---- + +[[step-4---start-restcomm-and-send-inbound-messages]] +Step 4 - Start Restcomm and Send inbound Messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Start Restcomm and make sure SMPP is correctly bound to Nexmo +* Create a new SMS RVD Application that will receive incoming SMS from Nexmo +* Attach your Nexmo Number to the application (See below) + +image:./images/restcomm-smpp-nexmo31.jpg[restcomm-smpp-nexmo3,width=635,height=364] + +* See the screenshot below (The number below is the one to attach to your RVD application) + +image:./images/restcomm-smpp-nexmo.jpg[restcomm-smpp-nexmo,width=478,height=248] + +* Send an SMS message to the Number registered in your Nexmo Dashboard. +* The Nexmo *Callback System-type* setting lets Nexmo know that the message should be sent to this particular instance of Restcomm + +[[step-5---send-outbound-sms-through-nexmo-smpp]] +Step 5 - Send Outbound SMS through Nexmo SMPP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To send an outbound message through Restcomm SMPP endpoint, you must specify the DID using as SIP phone or you can also build an app using Restcomm Visual Designer. + +Restcomm will check to see if there is a local application attached to that number. If there is none, the message will be forwarded through the SMPP connection to the provider, in this case, NEXMO. + +Example, if you want to send an SMS to the number 3399999999, you send it to 3399999999@RESTCOMM_IP:5080 + +See screenshot below: + +image:./images/restcomm-smpp-nexmo5.png[restcomm-smpp-nexmo5,width=466,height=343]] diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to Bandwidth for DID Calls.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to Bandwidth for DID Calls.adoc new file mode 100644 index 0000000000..b3487b77ea --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to Bandwidth for DID Calls.adoc @@ -0,0 +1,68 @@ +This tutorial is about how to connect Restcomm to Bandwidth and provision DIDs. Restcomm uses ports 5080 for SIP traffic while Bandwidth expects to receive traffic on port 5060. + +Normal SIP traffic will work using a SIP phone (ex sip:DID@RESTCOMM_IP:5080) but making a call from a PSTN to a DID provisioned by Bandwidth will not work as Restcomm replies using a different port. + +[[step-1---configure-restcomm-ip-address]] +Step 1 - Configure Restcomm IP Address +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Please see the instruction <> + +[[step-2---configure-restcomm-to-use-bandwidth]] +Step 2 - Configure Restcomm to use Bandwidth +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Edit the file *$RESTCOMM_HOME/bin/restcomm/restcomm.conf* Look for the section below and add your Bandwidth connection details + +[source,lang:default,decode:true] +---- +# DID Provision provider variable declarations +# values: VI (VoipInnovation), BW (Bandwidth), NX (Nexmo), VB (Voxbone) +PROVISION_PROVIDER='BW' +#Username and password for all supported DID provision providers +DID_LOGIN='YOUR_BANDWIDTH_LOGIN' +DID_PASSWORD='YOUR_BANDWIDTH_PWD' +---- + +Save and exit file + +[[step-3---configure-standalone-sip.xml-to-use-5060-instead-of-5080]] +Step 3 - Configure **standalone-sip.xm**l to use 5060 instead of 5080 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Open and Edit the file *RESTCOMM_HOME/standalone/configuration/standalone-sip.xml* + +* Got to the section + +[source,lang:default,decode:true] +---- + + + + + + +---- + +* Change all the ports from 508x to 516x as follows + +[source,lang:default,decode:true] +---- + + + + + + +---- + +* Save and exit the file +* Restart Restcomm + +[[making-future-sip-calls]] +Making future SIP Calls +^^^^^^^^^^^^^^^^^^^^^^^ + +You will now need to use port 5060 to make calls from a SIP phone as follows: sip:DID@RESTCOMM_IP:5060 + +  diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to French Legos SIP BornSIP Trunk.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to French Legos SIP BornSIP Trunk.adoc new file mode 100644 index 0000000000..979fa43ee0 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Connecting to French Legos SIP BornSIP Trunk.adoc @@ -0,0 +1,55 @@ +Restcomm is a next generation Cloud Communications Platform to rapidly build voice and text messaging applications, using mainstream web development skills. Restcomm is a turnkey Cloud Communications solution from Telestax. + +[[requirements]] +Requirements +^^^^^^^^^^^^ + +* Restcomm running : <> +* Go to the website of Legos to get an account http://www.legos.fr/en/services-2/sip-trunk/[HERE] + +Legos will give you the followng configuration information + +[source,lang:default,decode:true] +---- +SIP Trunk Server : XXX.bornsip.XXX +Trunk Authentication Id : AuthenticaionIDXXXXXXXX +Trunk Password : AuthPasswordXXXXXXXXX +Outbound CallerID : CallerIDXXXXXXX +---- + +[[step-1---change-outbound-setting-in-the-read-user-data.sh-file]] +Step 1 - Change outbound setting in the read-user-data.sh file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Edit the read-user-data.sh  as follows (**ONLY FOR RESTCOMM ON AMAZON CLOUD**) +* #Change the Outbound proxy to '' *export OUTBOUND_PROXY=$(readUserData OUTBOUND_PROXY 'XXX.bornsip.XXX')* +* Disable the Telestax proxy by setting the following line to 'false' +* *export ACTIVE_PROXY=$(readUserData active_proxy 'false')* + +[[step-2---edit-restcomm.conf-file]] +Step 2 - Edit restcomm.conf file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Go to the $Restcomm_HOME/bin/restcomm/restcomm.conf file and edit the following lines +[source,lang:default,decode:true] +---- +# Address for outbound calls +OUTBOUND_PROXY='XXX.bornsip.XXX' +OUTBOUND_PROXY_USERNAME='AuthenticaionIDXXXXXXX' +OUTBOUND_PROXY_PASSWORD='AuthPasswordXXXXXXXXX' +---- + +[[step-3---edit-restcomm.xml]] +Step 3 - Edit restcomm.xml +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In the *$Restcomm_HOME/standalone/deployments/restcomm.war/WEB-INF/conf/restcomm.xml* +* Search for the tag ** the value must be set to "true" +* *true* + +[[step-4---restart-restcomm]] +Step 4 - Restart Restcomm +^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Restart Restcomm and make a call to a PSTN in France. +* The CallerID of the SIP phone you use to make the call should be CallerIDXXXXXXX (Provided by Legos) diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable HTTPS secure connector on JBoss AS 7 or EAP 6.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable HTTPS secure connector on JBoss AS 7 or EAP 6.adoc new file mode 100644 index 0000000000..8ef42fa1c4 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable HTTPS secure connector on JBoss AS 7 or EAP 6.adoc @@ -0,0 +1,148 @@ +The configuration guide will show you how to create a keystore and activate SSL for HTTPS connection. + + +[[enable-https-secure-connector]] +Enable HTTPs Secure Connector +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Restcomm uses port 8080 for HTTP connector. The following instruction will guide you through the steps required to configure SSL and enable HTTPS. + +Make sure you are testing using the latest Restcomm. + + +[[step-1]] +Step 1 - Keystore by Certificate Authority (CA) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you will be using a self-signed certificate, you may skip the step and go to Step 2 + +If you are using a Certificate Authority (CA), create the keystore as instructed by the CA provider and copy the keystore to $RESTCOMM_HOME/standalone/configuration/ directory. +Next, go to step 3. + +Here is a link for a free Certificate Authority (CA). https://letsencrypt.org/ + + +[[step-2]] +Step 2 - Self-signed Certificate Keystore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +To create a self-signed certificate keystore, perform the following steps: + +[source,lang:default,decode:true] +---- +$JAVA_HOME/bin/keytool -genkey -alias restcomm -keyalg RSA -keystore  restcomm.jks +---- + +For this example, we shall use the password, "changeit". + +Also make sure that for first and last name (CN) you provide the hostname of the machine running Restcomm. Running the command should look like this: + +[source,lang:default,decode:true] +---- +Enter keystore password: changeit +Re-enter new password: changeit +What is your first and last name? +[Unknown]: HOSTNAME_HERE +What is the name of your organizational unit? +[Unknown]: +What is the name of your organization? +[Unknown]: +What is the name of your City or Locality? +[Unknown]: +What is the name of your State or Province? +[Unknown]: +What is the two-letter country code for this unit? +[Unknown]: +Is CN=HOSTNAME_HERE, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct? +[no]: yes + +Enter key password for +(RETURN if same as keystore password): {JUST PRESS RETURN} +---- + +* HOSTNAME : Must match content of the "/etc/hostname or /etc/hosts" file. + +Copy the generated self-signed keystore restcomm.jks to the configuration directory as shown below + +[source,lang:default,decode:true] +---- +$RESTCOMM_HOME/standalone/configuration/restcomm.jks +---- + + +[[step-3]] +Step 3 - Configure Restcomm Configuration Files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,lang:default,decode:true] +---- +$RESTCOMM_HOME/bin/restcomm/advanced.conf +---- + + +[source,lang:default,decode:true] +---- + +#Allowed values FALSE, SELF, AUTH. +#If SELF set self-signed certificate will be created. +#If AUTH, Authorized certificate will be used.Need to place the certificate at "$RESTCOMM_HOME/standalone/configuration/" +#To Disable use 'FALSE' +SECURESSL=SELF + +#HTTPS Settings +DISABLE_HTTP='false' #Control whether or not HTTP connector will be disabled. Values: true=HTTP connector will be disable, false=HTTP Connector will not be disabled, REDIRECT= http -> https redirection will be enabled (For CLI RestAPI requests when redirect is active https needs to be used). +TRUSTSTORE_FILE='restcomm.jks' #File should be located at $RESTCOMM_HOME/standalone/configuration folder. Provide just the name of the trustore file. Leave it blank to disable HTTPS +TRUSTSTORE_PASSWORD='changeit' #Password for the trustore file +TRUSTSTORE_ALIAS='restcomm' #The certificate alias + +---- + +If you are using a self-signed certificate, change the SSL_MODE value to SSL_MODE='allowall' +[source,lang:default,decode:true] +---- +SSL_MODE='allowall' #Control whether or not Restcomm will accept self-signed certificates. Values allowall=allow self-signed certificates, strict=don't allow self signed certificates +---- + +Go to the Restcomm Admin UI at the following URL + +[source,lang:default,decode:true] +---- +https://RESTCOMM_IP_ADDRESS:8443/ +---- + +If you want to access HTTPS using the default port 443 instead of Restcomm' default 8443, change the following options in the $RESTCOMM_HOME/bin/restcomm/restcomm.conf file. + +[source,lang:default,decode:true] +---- +#RestComm PORT configuration +HTTP_PORT='8080' #Port used for HTTP. Default 8080 +HTTPS_PORT='8443' #Port used for HTTPS. Default 8443 + +---- + +Restcomm will now be accessible using the following URL : https://RESTCOMM_IP_ADDRESS/ + + +[[exception-download-rcml]] +Error - Exception while trying to download RCML +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you get the above message in the Restcomm server logs when making a call with HTTPS activated, you need to modify the restcomm.conf file by updating the following parameter: + +[source,lang:default,decode:true] +---- +#hostname of the server to be used at restcomm.xml. If not set the STATIC_ADDRESS will be used. +RESTCOMM_HOSTNAME='YOUR_HOST_NAME' + +---- + + +The above hostname must match the one in the /etc/hosts file and must also be the same hostname in your SSL certificate. + + + +For any questions or suggestions, please use the following channels: + +* Restcomm forum: https://groups.google.com/forum/#!forum/restcomm +* Stack Overflow: http://stackoverflow.com/questions/tagged/restcomm (remember to tag your questions with 'restcomm') +* Gitter #Restcomm-Discuss channel at https://gitter.im/RestComm/Restcomm-discuss diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable password reset URL.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable password reset URL.adoc new file mode 100644 index 0000000000..42caa86278 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Enable password reset URL.adoc @@ -0,0 +1,21 @@ +Restcomm does not provide built-in support for resetting the password of an account. +A seperate external service should be provided for this. However, if such +a service exists, __Dashboard__ can be configured to redirect the user +to this service through a 'Forgot password ?' prompt. + +In order to enable the 'Forgot password ?' prompt: + +* Edit dashboard configuration file located here: + + {RESTCOMM_HOME}/standalone/deployments/restcomm-management.war/conf/dashboard.json + +* Set `resetPasswordUrl` property to the *absolute* url of the actual + password reset service. For example: + + { + "resetPasswordUrl": "http://restcomm.aux/resetPassword" + } + +Once set, a 'Forgot password ?' link will be displayed under the login form +of Dashboard. When the user clicks on it a new browser tab will open +at the location specified in the url. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Add G729 Codec to the Media Server.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Add G729 Codec to the Media Server.adoc new file mode 100644 index 0000000000..80a2d17449 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Add G729 Codec to the Media Server.adoc @@ -0,0 +1,69 @@ +[[add-g729-to-rms]] +Add G729 Codec to the Restcomm Media Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +IMPORTANT: Restcomm Connect ships with G.729 codec. G.729 includes patents from several companies and is licensed by Sipro Lab Telecom. Sipro Lab Telecom is the authorized Intellectual Property Licensing Administrator for G.729 technology and patent pool. + +*In a number of countries, the use of G.729 may require a license fee and/or royalty fee.* + +[[change-the-media-server-configuration]] +Change the Media Server configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Go to $RESTCOMM_HOME/mediaserver/deploy/server-beans.xml +* Find the Signal processort factory section as shown below + +.... + + + + + org.mobicents.media.server.impl.dsp.audio.l16.Encoder + org.mobicents.media.server.impl.dsp.audio.l16.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Decoder + org.mobicents.media.server.impl.dsp.audio.gsm.Encoder + org.mobicents.media.server.impl.dsp.audio.gsm.Decoder + + + +.... + +* Edit the section to add the G729 codec as shown below + +[source,lang:default,decode:true] +---- + + + + + org.mobicents.media.server.impl.dsp.audio.l16.Encoder + org.mobicents.media.server.impl.dsp.audio.l16.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.alaw.Decoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Encoder + org.mobicents.media.server.impl.dsp.audio.g711.ulaw.Decoder + org.mobicents.media.server.impl.dsp.audio.gsm.Encoder + org.mobicents.media.server.impl.dsp.audio.gsm.Decoder + org.mobicents.media.server.impl.dsp.audio.g729.Encoder + org.mobicents.media.server.impl.dsp.audio.g729.Decoder + + + +---- + +  + +[[remove-the-g729-codec-from-the-media-server]] +remove the G729 codec from the media server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Remove the g729 codec from the *$RESTCOMM_HOME/mediaserver/deploy/server-beans.xml* file + +[source,lang:default,decode:true] +---- + org.mobicents.media.server.impl.dsp.audio.g729.Encoder + org.mobicents.media.server.impl.dsp.audio.g729.Decoder +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Reset Admin Password.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Reset Admin Password.adoc new file mode 100644 index 0000000000..7feed1ad0a --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - How to Reset Admin Password.adoc @@ -0,0 +1,68 @@ +This tutorial will show you how you can easily reset the Restcomm Administrator's password. When you are starting with a new Restcomm installation, you will have to change the default password as explained http://docs.telestax.com/restcomm-change-default-password/[HERE]. For those who want to update their current password, the steps below will guide you through the process. + +1. The first part of the tutorial will show you how to reset the current Administrator's password +2. The second part will show you how to reset a forgotten Administrator's password. + += Requirements + +* Basic knowledge of Restcomm running on Amazon Cloud or on Local Server. +* Basic knowledge of Restcomm directory structure. + +[[reset-current-administrators-password]] += Reset Current Administrator's Password + +== Step 1 + +* Log into the Restcomm Admin UI *http://IP_ADDRESS:8080/restcomm-manangement* +* On the right top corner of the page, click on the menu *Default Administrator Account* +* Click on **Account Settings**, you will see a screen similar to the one below +* In the field **Password**, enter your new password and confirm +* Press the *Save* button to validate your changes + +image:./images/restcomm-pwd-reset.png[restcomm-pwd-reset,width=687,height=361] + +== Step 2 + +You must log out of the Restcomm Admin UI and log in again using the new password + +* On the right top corner of the page, click the menu *Default Administrator Account* +* Click on *Sign Out* +* Sign in using your new password  + +[[reset-forgotten-administrators-password]] += Reset Forgotten Administrators Password + +In order to perform the next step, you will need to edit the *restcomm.script* configuration file + +* Go to the directory *$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/data/hsql* +* Open the file *restcomm.script* for editing +* Replace the line below + +[source,lang:default,decode:true] +---- +INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24 00:00:00.000000','2015-01-19 07:34:08.157000','administrator@company.com','Default Administrator Account',NULL,'Full','active','b85b776645f22268b9ae197c65fe5f32','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf','ORafbe225ad37541eba518a74248f0ac4c') +---- + +* With the default one below + +*If you are running Restcomm 7.2.x,  replace the line with the INSERT below* + +[source,lang:default,decode:true] +---- +INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24','2012-04-24','administrator@company.com','Default Administrator Account',NULL,'Full','uninitialized','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf','ORafbe225ad37541eba518a74248f0ac4c') +---- + +*If you are running Restcomm 7.3.x and later, replace the line with the INSERT below* + +[source,lang:default,decode:true] +---- +INSERT INTO "restcomm_accounts" VALUES('ACae6e420f425248d6a26948c17a9e2acf','2012-04-24 00:00:00.000000','2012-04-24 00:00:00.000000','administrator@company.com','Default Administrator Account',NULL,'Full','uninitialized','77f8c12cc7b8f8423e5c38b035249166','Administrator','/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf') + +---- + +* Save the *restcomm.script* file +* Go to the directory *$RESTCOMM_HOME/bin/restcomm* +* Stop the running Restcomm instance by executing the script *./stop-restcomm.sh* +* Start Restcomm by executing the script *./start-restcomm.sh* + +IMPORTANT: You must have configured the restcomm.conf file in order to use the Stop and Start restcomm script. See http://docs.telestax.com/restcomm-understanding-autoconfigure-script/[HERE], under the section Using the Autoconfigure script.      diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Install and Configure Restcomm to use MariaDB.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Install and Configure Restcomm to use MariaDB.adoc new file mode 100644 index 0000000000..77b9535e1b --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Install and Configure Restcomm to use MariaDB.adoc @@ -0,0 +1,127 @@ +When working with the binary version of Restcomm, the default database is hsqlDB. This is of course not suitable for production but it is provided as a way for you to conveniently and quickly start up Restcomm. If you are running Restcomm on Amazon Cloud, the configuration and setup comes with MariaDB. For those who wish to run Restcomm on a local server or on another cloud based system, the following tutorial will show you how to get started with Restcomm and MariaDB + +[[requirements]] +Requirements +^^^^^^^^^^^^ + +* Make sure MariaDB is installed, for those run on systems that supports Yum install, see the instruction https://mariadb.com/kb/en/mariadb/yum/[HERE] +* Download the latest version of Restcomm-Connect as explained in <> + +[[step-1---adding-the-mariadb-jdbc-connector-to-jboss-datasource]] +Step 1 - Adding the MariaDB JDBC connector to JBoss Datasource +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Edit **$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml** file +* Under the datasource tag add the following: +* Make sure you are using the correct IP address and port default port 3306. In the example below the local IP is 192.168.1.3:3306 +* Use the correct username and password for the MariaDB access +* Set the MariaDB enabled="true" and make sure you set the default dummy datasource to "false" + +[source,lang:default,decode:true] +---- + + jdbc:mariadb://192.168.1.3:3306/restcomm + mariadb + TRANSACTION_READ_COMMITTED + + 100 + 200 + + + myTestUsername + myTestPassword + + + 100 + + + +---- + +* In the datasource under the *drivers* tag, add the following: +* save and exit the standalone-sip.xml file + +[source,lang:default,decode:true] +---- + + org.mariadb.jdbc.MySQLDataSource + +---- + +[[step-2---configuring-the-mybatis.xml-file-to-use-mariadb]] +Step 2 - Configuring the mybatis.xml file to use MariaDB +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Edit the file *$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/conf/mybatis.xml* +* Change the environments id to id="mariadb" +* Add the MariaDB configuration environment tag as shown below + +[source,lang:default,decode:true] +---- + + + + + + + + +---- + +* Save and exist the *mybatis.xml* file + +[[step-3---download-mariadb-java-client-driver]] +Step 3 - Download MariaDB Java Client Driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Download the mariaDB java client driver from link:https://mariadb.com/my_portal/download/java-client[HERE] +* Go to the directory *$RESTCOMM_HOME/modules* +* Run the following command to create a new directory structure:  *mkdir -p ./org/mariadb/jdbc/main* +* Go to the newly created directory structure *$RESTCOMM_HOME/modules/org/mariadb/jdbc/main* +* Copy the downloaded *mariadb-java-client-1.2.0.jar* to the *$RESTCOMM_HOME/modules/org/mariadb/jdbc/main* +* In the *$RESTCOMM_HOME/modules/org/mariadb/jdbc/main* create a new xml file called *module.xml* +* The content of the *module.xml* should be similar to the one below. Notice the *path* name of the java client must matches the one you download +* You should now have 2 files in the *$RESTCOMM_HOME/modules/org/mariadb/jdbc/main* directory. + +[source,lang:default,decode:true] +---- + + + + + + + + + + +---- + +[[step-4---start-mariadb-and-create-the-restcomm-database.]] + Step 4 - Start mariaDB and Create the restcomm Database. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Start mariaDB  - *sudo /etc/init.d/mysql start* +* Go to the directory *$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/scripts/mariadb* +* There will be an *init.sql* file and an *sql* directory +* Create the restcomm database from the *init.sql* as follows: +* mysql -u root < *init.sql* + +[[step-5---edit-the-restcomm.xml-file-to-point-the-dao-to-mariadb]] +Step 5 - Edit the restcomm.xml file to point the DAO to mariadb +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Edit the file **$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF**/conf/dao-manager.xml +* Find the dao-manager tag and change the sql-files path to mariadb as shown below + +[source,lang:default,decode:true] +---- + + ${restcomm:home}/WEB-INF/conf/mybatis.xml + + ${restcomm:home}/WEB-INF/data/hsql + ${restcomm:home}/WEB-INF/scripts/mariadb/sql + +---- + +Start Restcomm as explained in <> diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing Restcomm from GitHub.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing Restcomm from GitHub.adoc new file mode 100644 index 0000000000..5716535f69 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing Restcomm from GitHub.adoc @@ -0,0 +1,41 @@ +This tutorial will take you through the steps of installing Restcomm to a GNU/Linux box using the latest release from GitHub. + +[[prerequisites]] +Prerequisites +^^^^^^^^^^^^^ + +* A Linux box with Java 1.7 or higher installed +* Free VoiceRSS account for text to speech functionality + +[[installing-restcomm]] +Installing Restcomm +^^^^^^^^^^^^^^^^^^^ + +* Download link:https://github.com/Restcomm/RestComm-Connect/releases/latest[Restcomm latest release] and extract it: ++ +[source,theme:github,toolbar:1,lang:default,decode:true] +---- +$ unzip .zip +---- +* Go to link:http://www.voicerss.org and get a Text-to-Speech account. This is a free account that is required to activate Text-to-Speech in Restcomm. +* Navigate to $RESTCOMM/bin/restcomm/restcomm.conf and set the string you got from voicerss accordingly: ++ +[source,theme:github,toolbar:1,lang:default,decode:true] +---- +# VoiceRSS variable declarations +VOICERSS_KEY='' +---- +* From the same directory start Restcomm platform by executing: ++ +[source,theme:github,toolbar:1,lang:default,decode:true] +---- +./start-restcomm.sh +---- + +Now the Restcomm platform is up and running! You can experiment with it right away using the built-in Olympus WebRTC client that ships with Restcomm. + +Just open http://:8080/olympus and you are good to go! + +image:./images/olympus-1.jpg[Restcomm Olympus,width=1030,height=656] + +For more information on how to use Olympus please check out <> diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing on Google Cloud.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing on Google Cloud.adoc new file mode 100644 index 0000000000..b8b0699b99 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Installing on Google Cloud.adoc @@ -0,0 +1,99 @@ +Rescomm is a turn-key telephony SaaS solution ready for public or private cloud deployment. Restcomm is compatible with Twilio API’s and is part of the link:http://restcomm.org[Restcomm] open source Community. Here is the Restcomm Open Source community https://github.com/Restcomm/RestComm-Connect[github page]. + +This tutorial will guide you through the steps required to install and run Restcomm on Google Cloud Compute Engine. + +''''' + +[[requirements]] += Requirements + +* Basic Knowledge of Telscale Restcomm or Mobicents Restcomm +* Google Cloud Compute Engine as explained https://cloud.google.com/compute/docs/[HERE] +* Java JDK 7 or higher as explained http://tecadmin.net/steps-to-install-java-on-centos-5-6-or-rhel-5-6/[HERE] +* Install screen (**yum install screen**) +* Minimum compute engine "Machine-type" *g1-small (1 vCPU, 1.7 GB memory)* On a production server, increase the machine type to account for higher traffic. + +''''' + +[[initial-setup-and-installing-restcomm]] += Initial Setup and Installing Restcomm + +* ssh into your google cloud compute instance +* install "screen" +** *yum install screen* +* Download Java +** *download java jdk to the /opt directory of your install as follows* +** *wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz"* +** extract the content of the file to the */opt* directory as follows +** t**ar xzf jdk-7u79-linux-x64.tar.gz** +** point the java command to the correct directory with the following command +** *alternatives --config java* +* open firewall ports for Restcomm http traffic and RTP traffic +** from the ssh terminal run the following command +** *gcloud compute firewall-rules update restcomm-rules --allow tcp:444 tcp:8080 tcp:8000 tcp:2080 udp:5060 udp:5061 udp:5080 udp:34534-65535* +** these are some of the essential ports for SIP, RTP traffic. +* download  Mobicents Restcomm +** download Restcomm to any directory of your choice.* (In this tutorial, we created a new directory called telestax)* +** *wget https://mobicents.ci.cloudbees.com/view/RestComm/job/RestComm/lastSuccessfulBuild/artifact/mobicents-Restcomm-JBoss-AS7-7.2.2.611.zip* +** in the directory telestax extract the content of the zip file +** unzip *mobicents-Restcomm-JBoss-AS7-7.2.2.611.zip* +** go into the newly created **mobicents-Restcomm-JBoss-AS7-7.2.2.611** directory +** you should see the following content ++ +[source,lang:default,decode:true] +---- +appclient docs modules telestax-license.xml +bin domain README.txt telscale-media +bundles jboss-modules.jar standalone tools +copyright.txt LICENSE.txt Telestax-EULA.pdf welcome-content +---- + +[[config-and-start-restcomm]] += Configure and Start Restcomm + +** go to the directory **mobicents-Restcomm-JBoss-AS7-7.2.2.611**/bin/restcomm +** edit the file *restcomm.conf* file with the info from you google compute instance +** run the command *ifconfig* to get your local network details +** run the command *gcloud compute instances list* to get the Public IP Address +** go to *voicerss.org* to get a free API account +** fill out the *restcomm.conf* file as follows ++ +[source,lang:default,decode:true] +---- +# Network configuration +NET_INTERFACE=eth0 +PRIVATE_IP=10.240.203.100 +SUBNET_MASK=255.255.255.255 +NETWORK=10.240.203.100 +BROADCAST_ADDRESS=10.240.203.100 + +# PUBLIC IP ADDRESS +STATIC_ADDRESS=104.197.21.130 + +# VoiceRSS variable declarations +VOICERSS_KEY='290adfae344sdfgssfgs56d4c72b7' +---- + +[[start-and-use-restcomm]] += Start and Use Restcomm + +** run the start script in the directory mobicents-Restcomm-JBoss-AS7-7.2.2.611/bin/restcomm +** *./start-restcomm.sh* +** on your web browser go to the url +** *http://104.197.21.130:8080/* +** log into the Restcomm instance with username=**administrator@company.com** +** password=**RestComm** +** You will be prompted to change the default password. + +[[restcomm-login-page]] +image:./images/restcomm-login-page.png[restcomm-login-page,width=623,height=438] + +''''' + +[[section]] + +[[making-sip-calls-to-restcomm]] += Making SIP Calls to Restcomm + +* Start a SIP phone and make a call to *sip:1234@104.197.21.130:5080* +* Make another call to *sip:1235@104.197.21.130:5080* diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Integration with Dialogic XMS.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Integration with Dialogic XMS.adoc new file mode 100644 index 0000000000..9911482957 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Integration with Dialogic XMS.adoc @@ -0,0 +1,205 @@ +RestComm and PowerMedia XMS integration +======================================= + +RestComm is a next generation Cloud Communications Platform. +It allows web developers to rapidly build voice, video, WebRTC, USSD, SMS, fax and rich messaging applications. + + +Quick User Guide +---------------- + + + +RestComm installation and start +------------------------------- + +• Download the latest Restcomm Connect binary. +https://github.com/RestComm/Restcomm-Connect/releases/tag/7.9.0.1006 + +• Extract the content of Restcomm-JBoss-AS7-XX.XX.zip to a local directory on your computer. +The directory into which the file is extracted will be referred to as $RESTCOMM_HOME. + +• Open the terminal and run "ifconfig -a" to get the local ip address, broadcast and mask. + +• Go to $RESTCOMM_HOME/bin/restcomm and change the network configuration in restcomm.conf. + +.Example: +[source] +-------- +NET_INTERFACE='wlan0' +PRIVATE_IP=192.168.1.10 +SUBNET_MASK=255.255.255.0 +NETWORK=192.168.1.0 +BROADCAST_ADDRESS=192.168.1.255 +-------- + +• Set MS_COMPATIBILITY_MODE and XMS IP address. + +.Example: +[source] +-------- +MS_EXTERNAL=FALSE +MS_COMPATIBILITY_MODE='xms' + +MS_ADDRESS=192.168.1.100 +MS_NETWORK=192.168.1.0 +MS_SUBNET_MASK=255.255.255.0 +-------- + +[source] +-------- +VOICERSS_KEY='xxxxxxxxxxxxxxxxxxxxx' +-------- +NOTE: To generate your own voicerss API key, go to voicerss.org and register. + +• Go to $RESTCOMM_HOME/bin/restcomm and run: +[source] +-------- +sudo ./start-restcomm.sh +-------- + +Running in standalone mode +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +• Go to $RESTCOMM_HOME/standalone/configuration and edit standalone-sip.xml + +• Set the enable-welcome-root to false. +[source, xml] + + + + + +• Go to $RESTCOMM_HOME/standalone/deployments/ restcomm.war/WEB-INF/conf and edit restcomm.xml +[source, xml] + + xms + +
192.168.1.100
+ 5060 + udp + 5 +
+
+ + +• Start the Restcomm in standalone mode and bind to an address +[source] +sudo bash standalone.sh -b 192.168.1.10 + + +PowerMedia XMS Installation +--------------------------- + +This section provides the steps required to successfully install PowerMedia XMS. + +There are two installation methods available: + +• ISO Method +• RPM Method (used for a CentOS or RHEL installation). + +The following instructions pertain to the PowerMedia XMS download package, labeled as +PowerMedia-3.0.xxxx-x86_64.iso and dialogic_xms_3.0.xxxx.tgz where "xxxx" indicates the +version number. + + +NOTE: 32-bit operating systems are not supported. + + +Installation methods +~~~~~~~~~~~~~~~~~~~~ +• ISO Method Installation: +Community ENTerprise Operating System (CentOS) 7.x + +• RPM Method Installation: +CentOS 7.x and 6.4 (or later) +Red Hat Enterprise Linux (RHEL) 7.x and 6.4 (or later) +Oracle Enterprise Linux (OEL) 6.4 + +Download the .ISO file, which contains CentOS and PowerMedia XMS packages. +Go to http://www.dialogic.com/products/media-server-software/xms for information about downloading the .ISO file. + +NOTE: For detailed documentation refer to http://www.dialogic.com/webhelp/XMS/3.0/XMS_InstallConfig.pdf + +Supported Virtual Machines +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The supported virtual machines (VM) are: + +• VMWare ESXi 5.x +• Kernel Virtual Machine (KVM) +• XenServer VM +• Oracle VM VirtualBox + + +XMS installation in Oracle VM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Create new virtual machine (VM) + +• Name: Any suitable name (XMS) +• Type: Linux +• Version: Other Linux operating system 64 bit +• Recommended memory size 1024 MB +• Create a virtual hard disk + + +Select the following options while setting the virtual machine: + +• VDI (VirtualBox disk image) +• Dynamically allocated hard disk +• Recommended size 8GB + +Go ahead and press the Create button to finish up this part of the process. + + +Find and select the newly created virtual machine. + +• Open the Settings for the created VM. +Under "Storage", press "Add optical drive" and select the PowerMedia .iso file image. + +• In case there is Empty storage attachment in the storage tree, delete first. + + +Start the VM and choose between DHCP and Static IP installation. +The Static IP option is preferable when setting up a server. +Select the second option and press "Tab". + +Refer to the following example when setting static ip address +[source] +-------- +ip=192.168.1.100::192.168.1.1:255.255.255.0:server.xms30.com::none nameserver=8.8.8.8 +-------- + +NOTE: The IP address should match the MS_ADDRESS in the restcomm.conf + +The install process will begin and the next prompt will be to select the installation destination. + + +Select "Automatically configure partitioning" and press "Done". +For manual configuration select "I will configure partitionig". + +When the partitioning is done, click "Begin installation". + +Once installed, open the Settings and change the boot order. + +• Under System, change the boot order. Select only “Hard Diskâ€. +• Change the network configuration under Network. Attach “Adapter 1†to “Bridged Adapter†and select wlan0. +• Reboot the VM + +Now we should have running XMS instance on CentOS. + +Troubleshooting +^^^^^^^^^^^^^^^ + +In case XMS doesn't have connection, check the ifcfg-enp0s3 config file. + +• Login as root. The "root" user’s default password is "powermedia". +• Go to /etc/sysconfig/network-scripts/ +• Open and modify ifcfg-enp0s3 config file. "sudo vi ifcfg-enp0s3" + +[source] +-------- +BOOTPROTO='static' +IPADDR=192.168.1.100 +NET_MASK=255.255.255.0 +ONBOOT='yes' diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Route SMS to SS7 SMPP via Telscale SMSC.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Route SMS to SS7 SMPP via Telscale SMSC.adoc new file mode 100644 index 0000000000..7cfdc4a043 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Route SMS to SS7 SMPP via Telscale SMSC.adoc @@ -0,0 +1,59 @@ +Restcomm is a communication platform that helps developers build telecom solutions rapidly. It comes with powerful tools that lets you integrate traditional telephony with modern SIP backed systems. For example, it is possible to build an application that will send SMS messages from Restcomm to to *SS7/SMPP* via *Restcomm SMSC* gateway. The configuration is intuitive and easy to implement. this tutorial will show you who to configure Restcomm and send an SMS to Restcomm SMSC gateway. If is assumed that the SMSC gateway is already configured to forward all SMS received to the appropriate SS7/SMPP servers.   + += Requirements + +* Basic knowledge of Restcomm +* Understanding of Restcomm SMSC gateway + += Step 1 + +In this step, you will need to tell Restcomm how to route the SMS taffic to the Restcomm SMSC gateway + +* Go to *$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/conf/restcomm.xml* +* Edit the section with the sms-aggregator tag as shown below +* In the *outbound-endpoint* tag, add the IP address and port of the Restcomm SMSC gateway +* You need to restart Restcomm for the changes to take effect. + +[source,lang:default,decode:true] +---- + + + SMSC_IPADDRESS:SMSC_PORT + +---- + += Step 2 + +In this step, you will need to build a simple SMS application using Restcomm Visual Designer (RVD) + +* Open you web browser and go to *http://RESTCOMM_IP_ADDRESS:8080/* +* First time login, username "administrator@company.com" and password : "RestComm" +* You will be prompted to change the password +* In the Admin UI dashboard, at the top of the page, click on the "VisualDesigner" link +* In the RVD front page, choose Voice. +* Create a new voice project +* Drag and drop an SMS verb to the application and enter the SMS message you want to send. +* Also provide "To" and "From" +* Go back to the *http://RESTCOMM_IP_ADDRESS:8080/* +* Go to the "**Numbers**" link +* Register a new phone number (ex. 5566) +* Press "**optional parameters**" link +* in the Voice URL option, point to the new voice application you just created using the RVD +* In the list of numbers available, make sure the new number you registered is visible. + += Step 3 + +You will need to make a SIP call to the application you just created using the phone number you registered. For this to work, the SIP client needs to be registered with Restcomm, you can login using alice or bob. See link:http://docs.telestax.com/restcomm-testing-default-demos/[Demos Apps] + +* make a call to call *sip:PHONE_NUMBER@RESTCOMM_IP_ADDRESS:5080* + +This will execute the application which will send SMS using the Restcomm SMSC server. + += Step 4 + +If you want to perform a quick test without using the Visual Designer, you can make an API call directly from the command line as follows. + +[source,lang:default,decode:true] +---- +curl -X POST -H 'application/json' 'http://ACCOUNT SID:AUTHENTICATION TOKEN@RESTCOMM_IP_ADDRESS:8080/restcomm/2012-04-24/Accounts/ACCOUNT SID/SMS/Messages.json' -d "From=NEW DID" -d "To=12356" -d "Body=Hello World" +---- diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Upgrade Process.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Upgrade Process.adoc new file mode 100644 index 0000000000..25454ab7ec --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Upgrade Process.adoc @@ -0,0 +1,21 @@ +In order to be able to use the latest features of Restcomm Connect, it is at times necessary to upgrade from a current version to the latest iteration. Telestax has made the upgrade procedure intuitive and fast. Please follow the steps below to upgrade Restcomm Connect from version your current version to the latest iteration. Before any major upgrade of a production server, we recommend that you backup your Amazon AMI instance: + +* See link:http://stackoverflow.com/questions/11323008/how-to-make-a-daily-back-up-of-my-ec2-instance[HERE] for how to back up your EC2 instance if you run on Amazon Web Services. + += Upgrade to latest version + +Stop restcomm by running + +* *restcomm_stop* + +Run the upgrade script as follows + +* *restcomm_update* + +Once the upgrade is finished, type + +* *source /etc/profile* + +Finally restart restcomm + +* *restcomm_start* diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Working with RestComm and Dialogic XMS.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Working with RestComm and Dialogic XMS.adoc new file mode 100644 index 0000000000..6ec1cde2e0 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm - Working with RestComm and Dialogic XMS.adoc @@ -0,0 +1,49 @@ +RestComm is a next generation Cloud Communications Platform. It allows web developers to rapidly build voice, video, WebRTC, USSD, SMS, fax and rich messaging applications. Restcomm opens new revenue streams for service providers by exposing existing SS7 and IMS core network assets to application developers. + +This documentation will explain how you can configure Dialogic XMS JSR-309 driver to work with Restcomm. + +[[automatic-configuration-and-startup]] +Automatic configuration and startup +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* *Download the Restcomm Connect binary* from link:https://github.com/Mobicents/RestComm/releases/tag/latest[latest release]. +* *Unzip the file to the directory of your choice.* This directory will be known as RESTCOMM_HOME from now on. +* *Modify $RESTCOMM_HOME/bin/restcomm/restcomm.conf* file by setting the variable *MS_ADDRESS* to the public address of your Dialogic XMS instance. +** A detailed guide to RestComm's automatic configuration and startup can be found link:http://docs.telestax.com/restcomm-understanding-autoconfigure-script[here]. +* **Start RestComm** using the **$JBOSS_HOME/bin/restcomm/restcomm-start.sh **script. + +An example of configuration for the RestComm startup mechanism can be found below: + +[source,lang:sh,decode:true] +---- +NET_INTERFACE=eth0 +PRIVATE_IP=192.168.1.175 +SUBNET_MASK=255.255.255.0 +NETWORK=192.168.1.0 +BROADCAST_ADDRESS=192.168.1.255 +#MEDIA SERVER COMPATIBILITY MODE (rms=RestComm Media Server, xms=Dialogic XMS) +MS_COMPATIBILITY_MODE='xms' +MS_ADRESS=54.22.56.57 + +---- + +[[creating-a-logger-for-jsr-309-connector]] +*Creating a Logger for JSR-309 Connector* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Go to the  *$JBOSS_HOME/standalone/configuration* folder +* Edit the file *standalone-sip.xml* +* Locate the tag +* Change the logger level to one of this options: DEBUG, INFO, WARN or ERROR +* As shown below the logger level is set to INFO + +[source,lang:default,decode:true] +---- + + + +---- + +#MEDIA SERVER COMPATIBILITY MODE (rms=RestComm Media Server, xms=Dialogic XMS) +MS_COMPATIBILITY_MODE='xms' +MS_ADDRESS='' diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm- Automatic Configuration Options.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm- Automatic Configuration Options.adoc new file mode 100644 index 0000000000..515e9e9673 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm- Automatic Configuration Options.adoc @@ -0,0 +1,126 @@ +[[restcomm-connect_configuration_options]] += Automatic Configuration Options for RestComm-Connect + +RestComm-Connect used two configuration files (restcomm.conf & advanced.conf) located at *$RESTCOMM_HOME/bin/restcomm*. directory. +At the continuation we are providing detailed explanation for each property available. + +TIP: A lot of the options explained here are available for a RestComm-connect version >= 7.8.0. + +===== Basic configuration options on restcomm.con File. + +* Section *#Network configuration*. Information can be found http://documentation.telestax.com/connect/configuration/Starting%20Restcomm-Connect.html#start-restcomm-connect[HERE] +[source,bash] +---- +#hostname of the server to be used at restcomm.xml. If not set the STATIC_ADDRESS will be used. +RESTCOMM_HOSTNAME='' + +# Activate music on conference when participants==1 +PLAY_WAIT_MUSIC='TRUE' +---- + +* Section *#Telscale MEDIA SERVER CONFIGURATION*. +[source,bash] +---- +#Media server running external (different node than Restcomm) +MS_EXTERNAL=FALSE +#MEDIA SERVER COMPATIBILITY MODE (mms=Mobicents Media Server, xms=Dialogic XMS) +MS_COMPATIBILITY_MODE='mms' + +#XMS IP ADDRESS or RMS IP ADDRESS if using different IP from RestComm +MS_ADDRESS='' +MS_NETWORK='' +MS_SUBNET_MASK='' + +# Media Server RTP ports +MEDIASERVER_LOWEST_PORT='' +MEDIASERVER_HIGHEST_PORT='' +MEDIASERVER_EXTERNAL_ADDRESS='' +#Medias server MGCP ports +LOCALMGCP=2727 +REMOTEMGCP=2427 + +# When working with external Media Server specify the location of the Recording files +RECORDINGS_PATH='' +#Other +USESBC=TRUE +#For in-Band DTMF +DTMFDBI='0' +#MGCP_TIMOUT +MGCP_RESPONSE_TIMEOUT=500 +---- + +* Section *#outbound proxy configuration*. +[source,bash] +---- +# Address for outbound calls +OUTBOUND_PROXY='' #Provide port if different than 5060 +OUTBOUND_PROXY_USERNAME='' +OUTBOUND_PROXY_PASSWORD='' + +# Outbound proxy for SMS +SMS_PREFIX='#' #For VoipInnovation you will need the '#' character for SMS Prefix +SMS_OUTBOUND_PROXY='' #Please provide port if different than 5060 + +---- + +* Section *#Restcomm SMPP integration*. +[source,bash] +---- +# Connection details for SMPP Restcomm integration +SMPP_ACTIVATE='false' #default SMPP activate is always false. Set to true to activate SMPP +SMPP_SYSTEM_ID='' +SMPP_PASSWORD='' +SMPP_SYSTEM_TYPE='' +SMPP_PEER_IP='' #use IP or DNS name of peer SMPP server +SMPP_PEER_PORT='' +SMPP_SOURCE_MAP='' +SMPP_DEST_MAP='' +---- + +* Section *#Restcomm DID provider integration*. +[source,bash] +---- +# DID Provision provider variable declarations +PROVISION_PROVIDER='' # values: BW (Bandwidth), NX (Nexmo), VB (Voxbone) +#Username and password for all supported DID provision providers +DID_LOGIN='' +DID_PASSWORD='' +---- + +* Section *#Text-to-speech*. +* Go to link:http://www.voicerss.org and get a Text-to-Speech account. This is a free account that is required to activate Text-to-Speech in Restcomm. +[source,bash] +---- +# VoiceRSS variable declarations +VOICERSS_KEY= +---- + +* Section *#RestComm PORT configuration*. +[source,bash] +---- +HTTP_PORT='8080' #Port used for HTTP. Default 8080 +HTTPS_PORT='8443' #Port used for HTTPS. Default 8443 +#Connectors port configuration +SIP_PORT_UDP='5080' #LB UDP port. Default is 5080 +SIP_PORT_TCP='5080' #LB TCP port. Default is 5080 +SIP_PORT_TLS='5081' #LB TLS port. Default is 5081 +SIP_PORT_WS='5082' #LB WS port. Default is 5082 +SIP_PORT_WSS='5083' #LB WSS port. Default is 5083 +#Port Offset Used when more that one RC is running on the same machine. To avoid port conflicts +#E.g. If set PORT_OFFSET='100' all configured ports will be accessible from PORT+100. +PORT_OFFSET='0' #Port offset configurations. Default '0'. +---- + +* Section *#LOGS level*. +[source,bash] +---- +#Usual values : WARN,INFO,DEBUG +LOG_LEVEL='INFO' #Used for RMS & RC console-handler. +LOG_LEVEL_COMPONENT_GOVNIST='INFO' #Log level for "gov.nist" module +LOG_LEVEL_COMPONENT_SIPSERVLET='INFO' #Log level for "org.mobicents.servlet" module + +#AKKA log level. Set the Log level for the AKKA actor system. +AKKA_LOG_LEVEL='INFO' +---- + +**For Advanced configuration options http://HERE[HERE]* diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm-Advanced Automatic Configuration Options.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm-Advanced Automatic Configuration Options.adoc new file mode 100644 index 0000000000..47e44102d3 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Restcomm-Advanced Automatic Configuration Options.adoc @@ -0,0 +1,180 @@ +[[restcomm-connect_advanced_configuration_options]] += Advanced Automatic Configuration Options for RestComm-Connect + +===== Advanced configuration options on advanced.con File. + +* Section *#Manual Configuration*. +[source,bash] +---- +#If set no automatic configuration will done. Everything needs to be set manually. +MANUAL_SETUP='FALSE' #Used to configure RestComm manually and not take under consideration restcomm.conf & advanced.conf files. +---- + +* Section *#Secure SSL configuration*. +[source,bash] +---- +#Allowed values FALSE, SELF, AUTH. +#If SELF set self-signed certificate will be created. +#If AUTH, Authorized certificate will be used.Need to place the certificate at "$RESTCOMM_HOME/standalone/configuration/" +#To Disable use 'FALSE' +SECURESSL=FALSE +TRUSTSTORE_FILE='restcomm-crt.jks' #File should be located at $RESTCOMM_HOME/standalone/configuration folder. Provide just the name of the trustore file. +TRUSTSTORE_PASSWORD='changeme' #Password for the trustore file +TRUSTSTORE_ALIAS='restcomm' #The certificate alias + +#HTTPS Settings +DISABLE_HTTP='false' #Control whether or not HTTP connector will be disabled. Values: "true"=HTTP connector will be disable, "false"=HTTP Connector will not be disabled, REDIRECT= http -> https redirection will be enabled (For CLI RestAPI requests when redirect is active https needs to be used). +#Control whether or not Restcomm will accept self-signed certificates. +SSL_MODE='strict' #Values allowall=allow self-signed certificates, strict=don't allow self signed certificates. If SECURESSL=SELFE set to "allowall" automatically. +---- + +* Section *#JAVA Options*. +[source,bash] +---- +#JVM Options used to RUN RC and RMS. +RC_JAVA_OPTS='-Xms1024m -Xmx4096m -Xmn512m -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycle=100 +-XX:CMSIncrementalDutyCycleMin=100 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:MaxPermSize=512m +-Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 + -Dsun.rmi.dgc.server.gcInterval=3600000' + +#RMS JAVA_OPTS +RMS_JAVA_OPTS='-Xms1024m -Xmx1024m -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1RSetUpdatingPauseTimePercent=10 +-XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=4m -XX:G1HeapWastePercent=5 -XX:InitiatingHeapOccupancyPercent=85 +-XX:+UnlockExperimentalVMOptions -XX:G1MixedGCLiveThresholdPercent=85 -XX:+AlwaysPreTouch -XX:+UseCompressedOops -Djava.net.preferIPv4Stack=true +-Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dhttp.keepAlive=false' +---- + +* Section *#JAdditional Connectors*. +[source,bash] +---- +#Add extra connectors if needed. Need to use the following rule: +#ADDITIONAL_CONNECTOR_X=CONNECTOR_NAME:PORT +#Available names:sip-tcp,sip-tcp,sip-tls,sip-ws,sip-wss +#More Info Here: http://documentation.telestax.com/core/sip_servlets/SIP_Servlets_Server_User_Guide.html +#Example: +#ADDITIONAL_CONNECTOR_1=second-sip-udp:5090 +#ADDITIONAL_CONNECTOR_2=second-sip-tcp:5090 +---- + +* Section *#MYSQL support*. +[source,bash] +---- +#Default: false. If not configured HSQL will be used. +ENABLE_MYSQL='false' +MYSQL_USER='' +MYSQL_PASSWORD='' +MYSQL_HOST='' +MYSQL_SCHEMA='' +MYSQL_SNDHOST='' #Used for DB redundancy. If set RestComm (Jboss) will point to it if principal DB fails. +---- + +[[amazons3]] +* Section *#Amazon S3 Bucket*. +[source,bash] +---- +#Used to store Recordings. +#Default: false. If not configured internal recordings directory will be used. +ACTIVATE_S3_BUCKET='FALSE' +S3_BUCKET_NAME='' +S3_ACCESS_KEY='' +S3_SECURITY_KEY='' +S3_BUCKET_REGION='' #If not set, "us-east-1" will be used. +---- + +* Section *#SMTP Configuration*. +[source,bash] +---- +#Used for system email notifications (When system errors occur). +#As well used for Restcomm email service (Email Verb). +SMTP_USER='' +SMTP_PASSWORD='' +SMTP_HOST='' +SMTP_PORT='' #If not set default Port will be used. Port 25. +---- + +* Section *#Configure Load Balancer*. +[source,bash] +---- +ACTIVATE_LB='FALSE' #Set to TRUE to activate and make Restcomm register with LB, the default is FALSE, +LB_PUBLIC_IP='' #The "external" IP of the Telestax LB. Is used for the incoming traffic. +LB_INTERNAL_IP='' #The "internal" IP of the LB. Is used for RC to connect to the LB. If not set LB_PUBLIC_IP will be used. +#Ports that used for interchange between RestComm and Load Balancer +#LB INTERNAL PORTS !!IMPORTANT!!: need to be set same values as LB is configured for the corresponding transport internal Ports. +LB_INTERNAL_PORT_UDP='5080' #LB internal port used from RC for UDP traffic. Default is 5080 +LB_INTERNAL_PORT_TCP='5080' #LB internal port used from RC for TCP traffic. Default is 5080 +LB_INTERNAL_PORT_TLS='5081' #LB internal port used from RC for TLS traffic. Default is 5081 +LB_INTERNAL_PORT_WS='5082' #LB internal port used from RC for WS traffic. Default is 5082 +LB_INTERNAL_PORT_WSS='5083' #LB internal port used from RC for WSS traffic. Default is 5083 +#LB External Ports !!IMPORTANT!!: Need to be set same values as LB is configured for the corresponding transport external Ports. +LB_EXTERNAL_PORT_UDP='5060' #LB external port of LB for UDP traffic. Default is 5060. +LB_EXTERNAL_PORT_TCP='5060' #LB external port of LB for UDP traffic. Default is 5060. +LB_EXTERNAL_PORT_TLS='5061' #LB external port of LB for TLS traffic. Default is 5061. +LB_EXTERNAL_PORT_WS='5062' #LB external port of LB for WS traffic. Default is 5062. +LB_EXTERNAL_PORT_WSS='5063' #LB external port of LB for WSS traffic. Default is 5063. (Port used for Olympus) + +#Load Balancer external HOSTNAME/IP & PORT. Must be set if RC under LB. +#Used to configure DID provider.This way PSTN calls going through LB. +#LB_EXTERNAL_PORT_UDP will be used for the DID provider PORT configuration. +LBHOST='' #Obligatory to set if Load Balancer is used for PSTN (DID provider configuration). + +---- + +* Section *#RVD configuration*. +[source,bash] +---- +#RVD workspace path. (If not set default will be used). +#Default: leave empty. +RVD_LOCATION=' +---- + +* Section *#RMS pool size*. +[source,bash] +---- +#Un-comment the resource that you want to set the pool size. +#RMS pool size (Should calculated from number of concurrent calls expected). +#RESOURCE_IVR=50 #max conc calls * 2 +#RESOURCE_CNF=50 #max concurrent calls +#RESOURCE_Bridge=50 #max concurrent calls +#RESOURCE_Relay=0 #Not used +---- + +* Section *#RestComm Monitoring*. +[source,bash] +---- +#Enabling following means that there is Graylog server running somewhere as well. +GRAYLOG_SERVER="" #IP of the Graylog server to send data. To disable please use empty string +SERVERLABEL="" #RestComm server Label, used to recognise server at Graylog server. +HD_MONITOR=false #Enable HD usage monitoring. +RCJVM_MONITOR=false #Enable JVM (Memory, CPU) usage monitoring for RC. Make sure that $JAVA_HOME/lib/tools.jar exist +RMSJVM_MONITOR=false #Enable JVM (Memory, RAM, CPU) usage monitoring for RMS. Make sure that $JAVA_HOME/lib/tools.jar exist +RAM_MONITOR=false #Enable overall RAM system monitoring. + +#Management User/Password configuration. Used for RestComm statistics consultation (Graylog). +#Jboss Management interface. More info https://docs.jboss.org/author/display/AS7/Management+resources +#Used for RestComm statistics consultation (Graylog). +MGMT_USER='' #Management Interface User configuration. +MGMT_PASS='' #Management Interface Password configuration. +---- + +* Section *#Other*. +[source,bash] +---- +#Other General configuration Options +#Directory where HSQL database will exist. If leave empty default value will be used. +#Default: leave empty. +HSQL_DIR='' +#Set Adminitrator Password when RestComm run first time. +#If not set default password ("RestComm") will be used. +INITIAL_ADMIN_PASSWORD='' +#SNI is to be an equivalent of Virtual Hosting but in HTTPS. +#It allows many different domains to be served over a single IP. +#Used in some cases that ES of RVD is not working. (Issue #725) +SSLSNI=TRUE #Enable/disable SNI (Server Name Indication). +#Used to set HTTP Response timeout for RC to download the RCML. +HTTP_RESPONSE_TIMEOUT=5000 + +#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 +---- + + diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Running Restcomm Binary on a Linux Server.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Running Restcomm Binary on a Linux Server.adoc new file mode 100644 index 0000000000..78eac4efad --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Running Restcomm Binary on a Linux Server.adoc @@ -0,0 +1,141 @@ +RestComm is a robust, powerful platform that will facilitate building comprehensive real-time communication solutions. The steps below will help you get started with ease.   + +* *On a production system, please take into consideration the following:* +* *Restcomm Media Server can get into a bad state and report "Too many open files" error because of Linux default value on the total number of file descriptors.* +* *You can go to the following sites to see how to increase the maximum number of open files in your server:* +** *http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/* +** *http://amitbhayani.blogspot.fr/2010/01/javanetsocketexception-too-many-open.html.* + += Running RestComm + +[[jboss-security]] +== JBoss Security + +Running a secure application is dependent on multiple factors. Restcomm runs on JBoss which implies that system security implemention can be handled at JBoss level. Please see the link below on how you can make your server environment more secure. https://community.jboss.org/wiki/SecureJboss?_sscc=t. + + +== Start Restcomm + +<> + += Testing the Demo Applications + +Restcomm comes prepackaged with multiple example applications designed to help you quickly get started. + +[[demo-1---testing-the-play-verb]] +== Demo 1 - Testing the Play Verb + +Start a SIP phone (see below) and dial `1234@127.0.0.1:5080` . You will hear a welcome message. + +WARNING: Some SIP phones have codec incompatibility issues, in the above example, we used Ekiga. You may also try Jitsi or Sflphone. + +*The application bound to the number 1234 can be found at* +.... + $RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/hello-play.xml. +.... + +[[demo-2---testing-say-verb]] +== Demo 2 - Testing Say Verb + +You must first activate Text-to-Speech before you can proceed.   + +NOTE: You must get an API key from http://www.voicerss.org in order to proceed with this section. You can register for a free account and an API key will be emailed to you. + +Once you have the API key, open the `$RESTCOMM_HOME/standalone/deployments/restcomm.war/WEB-INF/conf/restcomm.xml` file and find the speech-synthesizer VoiceRSS section. Add your API key as shown below and restart RestComm + +.... + + http://api.voicerss.org + 2901c0aXXXXXXXXXXXXXX +.... + +Start a SIP phone dial `1235@127.0.0.1:5080` . You will hear a welcome message in multiple languages. + +*The application bound to the number 1235 can be found at* +.... + $RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/hello-world.xml. +.... + +[[demo-3---testing-gather-verb]] +== Demo 3 - Testing Gather Verb + +This demo creates a simple IVR system + +NOTE: Activate DTMF using Ekiga Make sure your DTMF setting in Ekiga is set to RFC2833. In order to set it correctly, go to the menu Edit->Preference->Protocols->SIP Settings->DTMF Mode You may also use SFLPHONE instead of Ekiga + +Start a SIP phone dial `1236@127.0.0.1:5080` . You will hear a message asking you to enter a digit and press star. If the digit is correctly received, Restcomm will replay the number you entered. + +The application bound to the number 1236 can be found at +.... +$RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/gather/hello-gather.xml. +.... + +and + +.... +$RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/gather/gather.jsp. +.... + +[[demo-4---testing-the-dial-sip-noun]] +== Demo 4 - Testing the Dial Sip Noun + +This demo makes a call from one SIP phone to another. The Demo uses the SIP noun. You can calll any SIP account. All you have to do is change the content of the `dial-sip.xml` + +In order to use this demo, you may use the default accounts, Alice and Bob, and register them on two separate SIP phones. Start both SIP phones and make sure Alice and Bob are registerd with the password (1234). These users come pre-configured with Restcomm for test purposes. + +[[start-two-sip-phone-sessions]] +=== Start Two SIP Phone Sessions + +*If you are using the SIP sflphone here is what to do:* + +*Start first instance ex. - sflphone* + +*Start second instance ex. - sudo sflphone* + +In the application `dial-sip.xml` you can change the default to `sip:alice@127.0.0.1:5061?` + +This will allow you to make a call to Alice. Note that Alice must be registered on port 5061 for the call to succeed. + +From the the phone on which Bob is registerd, dial the number `1237`. + +The phone on which Alice is registered will ring and the connection will be made when you answer the call. + +*The application bound to the number 1237 can be found at* +.... +$RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/dial/sip/dial-sip.xml. +.... + +[[demo-5---testing-the-client-noun]] +== Demo 5 - Testing the Client Noun + +This demo makes a call from one SIP Client to Another. The demo uses the Client noun + +In order to use this demo, you must have user Alice and Bob registered on two separate SIP phones. Start both SIP phones and make sure Alice and Bob are registerd with the password (1234). These users come pre-configured with Restcomm for test purposes. + +From the phone on which Bob is registerd, dial the number `1238`. The phone on which Alice is registered will ring and the connection will be made when you answer the call. + +*The application bound to the number 1238 can be found at* +.... +$RESTCOMM_HOME/standalone/deployments/restcomm.war/demos/dial/client/dial-client.xml. +.... + +[[demo-6---testing-conference-noun]] +== Demo 6 - Testing Conference Noun + +This demo Lets a user join a conference as a moderator and the other user as a participant. The participant will dial `1310` and will hear a hold music. The moderator will dial `1311` and the hold music will stop and the conference will be started. + +Most SIP phones will require you to register before you can make a call. You can use the default accounts, Alice and Bob with password (1234)to register. + +From the phone on which Bob is registerd, dial the number `1310`. From the phone on which Alice is registered, dial `1311` + +*The application bound to the number 1310 and 1311 can be found at* +.... +http://127.0.0.1:8080/restcomm/demos/dial/conference/dial-conference.xml +.... + +and at + +.... +http://127.0.0.1:8080/restcomm/demos/dial/conference/dial-conference-moderator.xml +.... diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Starting Restcomm-Connect.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Starting Restcomm-Connect.adoc new file mode 100644 index 0000000000..7099c7e13a --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/Starting Restcomm-Connect.adoc @@ -0,0 +1,164 @@ +[[start-restcomm-connect]] += Starting Restcomm-Connect + +== Requirements + +* Install the link:https://www.linode.com/docs/networking/ssh/using-gnu-screen-to-manage-persistent-terminal-sessions[GNU screen] (it is optional but recommended) +* Install link:http://linuxaria.com/howto/linux-subnet-calculator-cidr[IPCalc] +* Install link:http://dev.mysql.com/doc/refman/5.7/en/installing.html[MySQL] +* You must have link:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html[JDK - 7] installed on your computer + +== Download and unzip Restcomm binary + +_If you you have already installed Restcomm you can <> at once_ + +* Go to a local directory on your computer and run the following command ( is the release version number): + +[source,bash] +---- +wget https://mobicents.ci.cloudbees.com/job/RestComm/lastSuccessfulBuild/artifact/Mobicents-Restcomm-JBoss-AS7-.zip +---- + +* Unzip the binary to a local directory. It should be similar to this one: +*Restcomm-JBoss-AS7-7.6.0.869.zip*. + Further we shall refer to this above Restcomm directory as the *$RESTCOMM_HOME*. + +[ip-information] +== Configure Restcomm IP information and Text-to-speech +=== Add your IP address +_A single host may have multiple IP addresses. +To get Restcomm working properly it is important to indicate the right IP address. +For local testing you can use localhost address (e.g. 127.0.0.1), in real working environment you will +need to use your public IP address._ + +* Go to the directory *$RESTCOMM_HOME/bin/restcomm*. +* Open the file *restcomm.conf*. +* Go to the section *# Network configuration*. You have to indicate the following information: + +[source,bash] +---- +# Network configuration +NET_INTERFACE='' +PRIVATE_IP='' +SUBNET_MASK='' +NETWORK='' +BROADCAST_ADDRESS='' +---- +==== Obtaining the network interface +* First you have to get the information on your network interface. Run the command: + +[source,bash] +---- + netstat -r +---- +* Picture below shows sample output for the command. +Your *network interface* you can find in the Iface column in the same row where Gateway is indicated (for example wlx60e32716068a). + +* You will have multiple rows for the same network interface. +One of the rows in the Destination column contains the *network address* (for example 172.21.0.0). + +image::images/10.png[] + +==== Obtaining the public IP +* In order to get your public ip address you should run the following command: + +[source,bash] +---- +ifconfig +---- +* You will have to find the same network interface name. +The information you will need can be found in the output: + +image::images/8.png[] + +* Your *IP address* (for example 172.21.0.107) you will see in +[source,bash] +---- +inet addr +---- + +* Your *subnet mask* (for example 255.255.255.0) you will see in +[source,bash] +---- +Mask +---- +* Your *broadcast address* (for example 172.21.0.255) you will see in +[source,bash] +---- +Bcast +---- +==== Network configuration +* Insert the network configuration details of your server in the following variables: + +[source,bash] +---- +# Network configuration +NET_INTERFACE='wlx60e32716068a' +PRIVATE_IP='172.21.0.107' +SUBNET_MASK='255.255.255.0' +NETWORK='172.21.0.0' +BROADCAST_ADDRESS='172.21.0.255' +---- + +=== Add your Text-to-Speech Key + +_Text-to-Speech (TTS) is the technology which enables mobile, desktop and web applications +to read text aloud. Voice RSS provides free Text-to-Speech API as web service. +This TTS API key allows to convert the text to speech without installation of special software._ + +* Register at link:http://www.voicerss.org[voicerss.org] and get your personal *VoiceRSS API key*. It is for free. + +* Go to *$RESTCOMM_HOME/bin/restcomm* and open *restcomm.conf* file. + +* Go to the *# VoiceRSS variable declarations* section. Add your VoiceRSS API key to the *VOICERSS_KEY* variable: + +[source,bash] +---- +# VoiceRSS variable declarations +#VOICERSS_KEY='797e69a254fc431b818bb37f35fb62df' +---- + +* Save and exit the restcomm.conf file. + +== Start Restcomm and Open the Admin GUI + +* Go to the *$RESTCOMM_HOME/bin/restcomm/* directory. + +* To start Restcomm and media server run the following command: +[source,bash] +---- +./start-restcomm.sh +---- + +* To see the Restcomm startup process run the following command (only works if you have screen installed): +[source,bash] +---- +screen -r restcomm +---- + +* To see the Restcomm Media Server startup process run the command: +[source,bash] +---- +screen -r mms +---- + +* Open your web browser and go to the url – *http://IP:8080*. +Instead of "IP" you should put your IP. + +* Log in with the *administrator@company.com* username and the *RestComm* password. +Then you should change the default password. + +* If you need to stop the Restcomm you need to go to *$RESTCOMM_HOME/bin/restcomm* +directory and run +[source,bash] +---- +./stop-restcomm.sh +---- +== Making Test SIP Calls using the Demo Apps + +* Open any SIP phone of your choice. +You may use *Olympus*. Here you can find link:http://docs.telestax.com/how-to-use-olympus-with-restcomm[how to use Olympus with Restcomm]. + +* Go to the *Contacts* and make a test call at +1234 number. You will hear the standard voice message that is 2-3 seconds long. + +image::images/15.png[] 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/dns/dns-provisioning.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/dns/dns-provisioning.adoc new file mode 100644 index 0000000000..00d6830f69 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/dns/dns-provisioning.adoc @@ -0,0 +1,52 @@ +[[intro]] += Restcomm DNS Provisioning Provider Integration + +Restcomm provides functionality to integrate with DNS hosting providers, this way you can create new organizations in restcomm on custom domains. + +Following configuration need to be provided in order to enable DNS provisioning when creating organizations + +[source,shell] +---- +DNS_PROVISIONING_ENABLED="TRUE" +DNS_PROVISIONING_CLASS="" +---- + +**DNS_PROVISIONING_ENABLED**: By default dns provisioning is disabled which means during organization api CRUD operations, restcomm will not send any requests to DNS hosting server. If we set it to true we have to provide following configurations. +**DNS_PROVISIONING_CLASS**: It represents the DNS provisioning manager class, the class that calls DNS hosting provider's services to perform CRUD operations. Developers can provide customer Class for any DNS server as long as it implements `org.restcomm.connect.dns.DnsProvisioningManager` + +== Amazon Route53 Configuration + +Following configuration are specific to amazon route 53. + +[source,shell] +---- +DNS_PROVISIONING_ENABLED="TRUE" +DNS_PROVISIONING_CLASS="org.restcomm.connect.telscale.dns.route53.Route53DnsProvisioningManager" +DNS_PROVISIONING_AWS_ROUTE53_A_VALUE="" +DNS_PROVISIONING_AWS_ROUTE53_SRV_VALUE="" +DNS_PROVISIONING_AWS_ROUTE53_ACCESS_KEY="" +DNS_PROVISIONING_AWS_ROUTE53_SECRET_KEY="" +DNS_PROVISIONING_AWS_ROUTE53_REGION="" +DNS_PROVISIONING_AWS_ROUTE53_TTL="" +DNS_PROVISIONING_AWS_ROUTE53_HOSTED_ZONE_ID="" +DNS_PROVISIONING_AWS_ROUTE53_IS_ALIAS="" +DNS_PROVISIONING_AWS_ROUTE53_ALIAS_EVALUATE_TARGET_HEALTH="" +DNS_PROVISIONING_AWS_ROUTE53_ALIAS_HOSTED_ZONE_ID="" +---- + +**DNS_PROVISIONING_AWS_ROUTE53_A_VALUE**: is address to which DNS Server will route traffic In a cluster, it can be public ip of loadbalancer or alias/domainName of a DNS entity (AWS ELB etc). +**DNS_PROVISIONING_AWS_ROUTE53_SRV_VALUE**: SRV destination server value (e.g sip.restcomm.com) +**DNS_PROVISIONING_AWS_ROUTE53_ACCESS_KEY**: aws access key to call their APIs. +**DNS_PROVISIONING_AWS_ROUTE53_SECRET_KEY**: aws secret key to call their APIs. +**DNS_PROVISIONING_AWS_ROUTE53_REGION**: The region to be used by the client. This will be used to determine both the ervice endpoint (eg: https://sns.us-west-1.amazonaws.com) and signing region (eg: us-west-1) for requests. +**DNS_PROVISIONING_AWS_ROUTE53_TTL**: Time to live in seconds, default is 3600 seconds +**DNS_PROVISIONING_AWS_ROUTE53_HOSTED_ZONE_ID**: The ID of the hosted zone that contains the resource record sets that you want to change. For example hosted zone id of domain `restcomm.com`, this can be get from aws management console. +**DNS_PROVISIONING_AWS_ROUTE53_IS_ALIAS**: Set this configuration to true if above DNS_PROVISIONING_AWS_ROUTE53_A_VALUE is an alias and not a IP-address/domain-name. Default value is false. Read more about aliases http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html[here]. + +[NOTE] +==== +If DNS_PROVISIONING_AWS_ROUTE53_A_VALUE is an alias and DNS_PROVISIONING_AWS_ROUTE53_IS_ALIAS is set to true: we need to provide further configuration for +==== + +**DNS_PROVISIONING_AWS_ROUTE53_ALIAS_EVALUATE_TARGET_HEALTH**: Boolean to either evaluate target health or not, default is false. +**DNS_PROVISIONING_AWS_ROUTE53_ALIAS_HOSTED_ZONE_ID**: The ID of the hosted zone of the alias. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/docker/Restcomm - Docker Quick Start Guide.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/docker/Restcomm - Docker Quick Start Guide.adoc new file mode 100644 index 0000000000..5832c83fd3 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/docker/Restcomm - Docker Quick Start Guide.adoc @@ -0,0 +1,106 @@ += Quick Start Guide: RestComm on Docker +:toc: + +This is a quick user guide for running Restcomm on Docker. You will learn how to install and start using Restcomm in a docker container. + +[[prerequisites]] +Prerequisites +^^^^^^^^^^^^^^ + +* *Docker:* Just in case you don't have Docker installed already: https://docs.docker.com/engine/installation/ +* *Docker-Compose*: Make sure you follow the official installation guide for your platform: https://docs.docker.com/compose/install/ +* *System requirements:* Please ensure you have allowed Docker to run with enough memory. Restcomm requires minimum *3GB* to start 2 java processes: Jboss with Restcomm services and standalone mediaserver. +* *Enabling Text-to-Speech:* Get a free API KEY VoiceRss account as explained  http://www.voicerss.org/[HERE] +* *Firewall:* RestComm is a system that relies heavily on network. Ensure there is no firewall blocking any ports that RestComm relies on (you can find them in `docker-compose.yml`). If in doubt, temporarily disable your firewall to ensure that is not the cause of your problems. +* *SELinux:* This has been known to cause "permission denied" issues on some Linux system, you might want to disable or set SELinux to permissive mode.* (_hint_: getenforce, will show the type of permission you currently have ) + +[[run-restcomm]] +Run RestComm +^^^^^^^^^^^^ + +RestComm-Connect includes a single `docker-compose.yml` file, which is meant to document how the RestComm Docker image should be deployed. + +It comes with sane defaults for a standalone development environment, so it should pretty much work out of the box. + +1. Make sure you set your the local ethernet/wifi IP address on your laptop as the value for `RCBCONF_STATIC_ADDRESS`. +1. Get an API key for Text-to-Speech and set it as the value for `RCBCONF_VOICERSS_KEY`. +1. To try it all out, change to the folder where `docker-compose.yml` is located and run: + +[source:bash] +---- +$ docker-compose up +---- + + +[[supported-tags]] +Supported Tags +^^^^^^^^^^^^^^ + +A note on the docker image tags: + +* Tag "latest". Points to the latest binary from the Continuous Delivery server. Uses the https://github.com/RestComm/Restcomm-Connect[master] development branch : restcomm/restcomm:latest. *We don't advice to use "latest" tag for production as it is constantly changing, and as well new features and fixes may not be documented. +* We provide specific tags for GA releases (e.g. v770ga). Prefer to use release tags over `latest`, to avoid accidental updates. + + +[[quick-test]] +Quick test: Verify it works! +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Go to *https://RCBCONF_STATIC_ADDRESS:8443/olympus* +2. Press "Sign in" (username alice or bob and password 1234) +3. Your browser will ask for permission to share microphone and camera, press allow +4. Go to "Contact", click on the "**+1234**" and press the "Audio Call" button (phone icon) +5. You should hear the "Welcome to RestComm, a Telestax Sponsored project" announcement +6. You can also make a call to the "**+1235**" to test your Text-to-Speech configuration. (Remember to ensure you provided a correct VoiceRSS key!) + +[[accessing-the-admin-ui]] +Accessing the Admin UI +^^^^^^^^^^^^^^^^^^^^^^ + +1. Go to https://RCBCONF_STATIC_ADDRESS:8443 +2. Username = administrator@company.com +3. Password = RestComm +4. Change the default password + +[NOTE] +Using the flag "INIT_PASSWORD" you can set administrator password when running RestComm for first time. + More info http://documentation.telestax.com/connect/configuration/docker/Restcomm%20-%20Docker%20Environment%20Variables.html[RestComm-Docker Documentation] + + +[[basic-docker-commands]] +Basic Docker commands +^^^^^^^^^^^^^^^^^^^^^ + + +Get a bash console for a running RestComm container: +[source,lang:default,decode:true] +---- +docker exec -it RESTCOMM_Container_ID bash +---- + +''''' + +[[troubleshooting]] +Troubleshooting ++++++++++++++++ + +*Ubuntu 17.10 Docker Compose version* + +Please ensure you follow the official [docker](https://docs.docker.com/engine/installation/) and [docker-compose](https://docs.docker.com/compose/install/) installation guides, to ensure you are on a compatible docker version. + +*Excessive demand on memory when exposing a big range of ports.* + +Due to a known https://github.com/docker/docker/issues/11185[issue] on Docker, exposing a big range of ports produce a big need in RAM. On RestComm the issue arises when a big range of RTP ports is exposed. For a system with 4Gb of RAM a range of 50 ports is a good approach (e.g -p 65000-65050:65000-65050/udp). *We are expecting that this issue will be solved soon from Docker team.* + +Consider using the Docker Host network as a workaround for this: https://docs.docker.com/engine/reference/run/#network-settings + + +*Important Notice for RestComm networking* + +When using a SIP client that is not running on the same local machine as the RestComm docker container, call-setup through SIP/SDP/RTP will fail as the docker container runs on a different network segment. You must set the `RCBCONF_STATIC_ADDRESS` environment variable to address this. + +*Known Issue on Firefox when running RestComm Olympus* + +It is possible that you will not be able to log in to olympus the first time that you will try to connect using Firefox. To fix this problem please follow the solution provided by http://stackoverflow.com/users/379916/faisal-mq[Faisal Mq] (http://stackoverflow.com/questions/11542460/secure-websocket-wss-doesnt-work-on-firefox[stackoverflow]). + +* When you would try to open up wss say using wss://RCBCONF_STATIC_ADDRESS:5083, Firefox will keep on giving you error until you open up a separate Firefox tab and do try hitting URL [https]://RCBCONF_STATIC_ADDRESS:5083 and Confirm Security Exception (like you do on Firefox normally for any https based connection). This only happens in Firefox. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Configuring Load-balancer.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Configuring Load-balancer.adoc new file mode 100644 index 0000000000..488975ac8c --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Configuring Load-balancer.adoc @@ -0,0 +1,127 @@ +This tutorial focuses on how to use Telscale Loadbalancer to distribute SIP traffic between two Restcomm Servers. The diagram below shows the network topology. + +image:./images/Telscale-load-balancer-for-Restcomm.png[Telscale load balancer for Restcomm,width=654,height=293] + +[[requirements]] +Requirements +^^^^^^^^^^^^ + +* Basic knowledge of Restcomm + +[[step-1---install-and-configure-telscale-load-balancer]] +Step 1 - Install and Configure Telscale Load Balancer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Restcomm Loader Balancer is packaged with Restcomm Connect. + +* You must copy the load balancer binary from the $RESTCOMM_HOME/tools/sip-balancer to the install directory of your server. +* In this example, the sip-balancer directory has been copied to /opt/telestax/sip-balancer +* You will see the following files in the sip-balancer directory: + +[source,lang:default,decode:true] +---- +lb-log4j.xml logs lb-configuration.properties sip-balancer-jar-with-dependencies.jar +---- + +open and edit the  file *lb-configuration.properties* file + +* change the *host* parameter to the IP address of the load balancer server + +[source,lang:default,decode:true] +---- +# The binding address of the load balancer +host=192.168.1.10 +---- + +* change the **externalPort**  variables to *5080* . +* Ports 5080 is the default port used by Restcomm + +[source,lang:default,decode:true] +---- +# The SIP port used where client should connect +externalPort=5080 +---- + +* Leave the rest of the variables as default, save and exit the *lb-configuration.properties* file +* Start the load balancer (as shown below) whilst you are in the directory */opt/telestax/sip-balancer* + +[source,lang:default,decode:true] +---- +java -DlogConfigFile=./lb-log4j.xml -jar ./sip-balancer-jar-with-dependencies.jar -mobicents-balancer-config=lb-configuration.properties +---- + +* If the server is successfully started, you will see an output similar to the one below: + +[source,lang:default,decode:true] +---- +********truncated************ +tStore=null javax.net.ssl.trustStorePassword=null +2016-02-25 01:05:23,104 INFO main - the sip stack timer gov.nist.javax.sip.stack.timers.DefaultSipTimer has been started +2016-02-25 01:05:23,334 INFO main - Sip Balancer started on external address 192.168.1, external port : 5080, internalPort : 5085 +2016-02-25 01:05:23,436 INFO main - HTTP LB listening on port 2080 +2016-02-25 01:05:24,285 INFO RMI TCP Connection(4)-192.168.1.10 - Balancer algorithm org.mobicents.tools.sip.balancer.CallIDAffinityBalancerAlgorithm loaded succesfully for cluster version = 0 +---- + +[[step-2---configure-restcomm-servers-to-point-to-the-load-balancer]] +Step 2 - Configure Restcomm Servers to Point to the Load Balancer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +[[restcomm-server-1]] +Restcomm Server 1 ++++++++++++++++++ + +* Open and edit the file  *$RESTCOMM_HOME/bin/restcomm/proxy.conf* as shown below + +[source,lang:default,decode:true] +---- +# Proxy variable declarations +ACTIVE_PROXY='true' # values: TRUE or FALSE +TP_LOGIN='' # Username +TP_PASSWORD='' # Password +INSTANCE_ID='' # EC2 Instance id (will be used as endpoint - VI or accountId - BW) +SITE_ID='' # Only for BW integration +PROXY_IP='192.168.1.10' # Public IP Address of the Telestax Proxy +PROXY_PRIVATE_IP='192.168.1.10' # Private IP Address of the Telestax Proxy +---- + +* Open and edit the file  *$RESTCOMM_HOME/bin/restcomm/restcomm.conf* as shown below + +[source,lang:default,decode:true] +---- +# Network configuration +NET_INTERFACE='eth1' +PRIVATE_IP='192.168.1.11' +SUBNET_MASK='255.255.255.0' +NETWORK='192.168.1.0' +BROADCAST_ADDRESS='192.168.1.255' +# PUBLIC IP ADDRESS +STATIC_ADDRESS='' +---- + +* Start Restcomm and you will see the following in the startup console + +[source,lang:default,decode:true] +---- +02:38:52,455 INFO [org.mobicents.ha.javax.sip.LoadBalancerHeartBeatingServiceImpl] (Timer-2) Keepalive: SIP Load Balancer Found! /192.168.1.11:5065:2080:2000 +---- + +* In the load balancer console, you will see the output below. + +[source,lang:default,decode:true] +---- +2016-02-25 01:05:24,287 INFO RMI TCP Connection(4)- 192.168.1.11 - NodeExpirationTimerTask Run NSync[SIPNode hostname[telscalerestcomcore01] ip[192.168.1.11] httpPort[8080] sslPort[8443] wsPort[5082] tcpPort[5080] udpPort[5080] version[0] ] added +---- + +[[restcomm-server-2]] +Restcomm Server 2 ++++++++++++++++++ + +* Repeat *Step 2* for Restcomm Server 2 using the IP address 192.168.1.12 + +[[step-3---making-a-call-to-the-load-balancer-from-restcomm]] +Step 3 - Making a Call to the Load Balancer from Restcomm +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Make a call to the SIP IP address of the load balancer sip:1234@192.168.1.10:5080 + +The load balancer will distribute the call evenly between the two Restcomm servers. The first call will go to 192.168.1.11 and the next call will go to 192.168.1.12. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Single RVD Workspace for two Restcomm Instances.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Single RVD Workspace for two Restcomm Instances.adoc new file mode 100644 index 0000000000..04549488ce --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Single RVD Workspace for two Restcomm Instances.adoc @@ -0,0 +1,69 @@ +It is possible to run Restcomm in a cluster mode where two Restcomm instances can use the same Mysql server as explained <<./Restcomm - Using a Single Mysql Database for 2 Restcomm Servers.adoc#requirements,HERE>>. In this tutorial, you will learn how to configure two Restcomm instances to share the same workspace. This means, any application created with Restcomm Visual Designer on any Restcomm server will be available and visible on both Servers. In order to be able to call these applications, you will need to point Restcomm to the same database (as explained <<./Restcomm - Using a Single Mysql Database for 2 Restcomm Servers.adoc#requirements,HERE>>) and the same RVD workspace. + +[[requirements]] +Requirements +^^^^^^^^^^^^ + +* Install NFS on your Linux Server +* Basic Knowledge of Restcomm +* This tutorial use a Redhat Linux Server + +image:./images/Two-Restcomm-Servers-Sharing-a-Single-RVD-Workspace-.png[Two Restcomm Servers Sharing a Single RVD Workspace,width=553,height=273] + +[[step-1---make-sure-nfs-is-started-and-export-server1-rvd-workspace]] +Step 1 - Make sure NFS is started and export Server1 RVD Workspace +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* On Restcomm server1, create a new directory */opt/telestax/restcomm-shared-workspace* +* Edit the */etc/exports* file and add the line below: + +[source,lang:default,decode:true] +---- +/opt/telestax/restcomm-shared-workspace 192.168.1.12(rw,sync,no_root_squash,no_subtree_check) +---- + +* The above will share the *restcomm-shared-space* directory and give read-write access to any NFS client from server (Restcomm Server2) *192.168.1.12* +* Save the changes above and run the command below for changes to take effect. +* *sudo service nfs reload* +* Log into the (Restcomm server2) 192.168.1.12 and make sure the NFS exported directory is visible. Run the command below. +* *showmount -e 192.168.1.11* +* You will see an output like the one below +* *Export list for 192.168.1.11: - /opt/telestax/restcomm-shared-workspace 192.168.1.12* + +[[step-2---mount-the-shared-directory-on-restcomm-server2]] +Step 2 - Mount the Shared directory on Restcomm server2 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* On Restcomm Server2, create a new directory /opt/telestax/restcomm-mount-shared-workspace +* *mkdir -p /opt/telestax/restcomm-mount-shared-workspace* +* mount the shared directory on Server1 to the new directory you created above +* **mount -t nfs 192.168.1.11:/opt/telestax/restcomm-shared-workspace**  */opt/telestax/restcomm-mount-shared-workspace* +* create a test file in the */opt/telestax/restcomm-mount-shared-workspace* +* *touch testfile.txt* +* This file will also be visible in the *opt/telestax/restcomm-shared-workspace* of Restcomm Server1 +* Make sure the NFS share directory will automount on server restart. Add the line below to the */etc/fstab* file + +[source,lang:default,decode:true] +---- +192.168.1.11:/opt/telestax/restcomm-shared-workspace /opt/telestax/restcomm-mount-shared-workspace nfs defaults 0 0 +---- + +[[step-3---change-the-default-rvd-workspace-on-restcomm-server1-to-use-the-nfs-directory]] +Step 3 - Change the default RVD workspace on Restcomm Server1 to use the NFS directory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Rename default RVD workspace to workspace-old as shown below +* *mv $RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace   $RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace-old* +* Create a new symbolic link directory that points to the NFS shared directory(replacing the default workspace directory) +* *sudo ln -s /opt/telestax/restcomm-shared-workspace   /opt/telestax/$RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace* +* Copy the content of the directory workspace-old to workspace.(This content will be visible to both servers) + +[[step-4---change-the-default-rvd-workspace-on-restcomm-server2-to-use-the-nfs-directory]] +Step 4 - Change the default RVD workspace on Restcomm Server2 to use the NFS directory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Rename default RVD workspace to workspace-old as shown below +* *mv $RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace   $RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace-old* +* Create a new symbolic link directory that points to the NFS mount shared directory(replacing the default workspace directory) +* *sudo ln -s /opt/telestax/restcomm-mount-shared-workspace   /opt/telestax/$RESTCOMM_HOME/standalone/deployments/restcomm-rvd.war/workspace* +* Note the difference above that the directory is the restcomm-mount-shared-workspace. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Using a Single Mysql Database for 2 Restcomm Servers.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Using a Single Mysql Database for 2 Restcomm Servers.adoc new file mode 100644 index 0000000000..efc7fd5981 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/Restcomm - Using a Single Mysql Database for 2 Restcomm Servers.adoc @@ -0,0 +1,58 @@ +This tutorial will show you how to configure two Restcomm instances to use the same Mysql Server instance. + +[[requirements]] +Requirements +~~~~~~~~~~~~ + +* Install Mysql +* Download the latest version of Restcomm Telscale as explained http://docs.telestax.com/restcomm-pages/[HERE] + +image:./images/2-Restcomm-Servers-Using-a-Single-Mysql-Server.png[2 Restcomm Servers Using a Single Mysql Server,width=413,height=283] + +[[step-1---configure-restcomm-server-1-to-use-mysql-database]] +Step 1 - Configure Restcomm Server 1 to use Mysql Database +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Configure the first Restcomm Server1 to use Mysql as explained in the documentation http://docs.telestax.com/restcomm-install-and-configure-restcomm-to-use-mysql/[HERE] + +* On Restcomm server1 with IP *(192.168.1.11)* grant access to the Mysql Server so that Restcomm Server2 *(192.168.1.12)* will be able to access the restcomm. +* On Restcomm server1 access the mysql server; +* *mysql -u root -p* +* enter the root password +* make sure restcomm database is created :  *show databases;* +* grant access to servers from the same subnet as shown below +* ALTER USER PRIVILEGES ON \*.* TO 'root'@'192.168.1.%' IDENTIFIED BY 'rootUserPWD' WITH GRANT OPTION; + +[[step-2---configure-restcomm-server2-to-use-mysql-database-running-on-192.168.1.11]] +Step 2 - Configure Restcomm Server2 to use Mysql Database running on 192.168.1.11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Configure Restcomm Server2 as explained in the documentation http://docs.telestax.com/restcomm-install-and-configure-restcomm-to-use-mysql/[HERE]: + +* In step 1 of the documentation above, you have to edit **$RESTCOMM_HOME/standalone/configuration/standalone-sip.xml** +* change the IP address to point to the Mysql instanced running on Restcomm Server1 as follows: ****jdbc:mysql://192.168.1.11:3306/restcomm**** +* See full snapshot below: +* Complete steps 2 - 5 as explained in the documentation *Install and configure Restcomm to use Mysql* + +[source,lang:default,decode:true] +---- + + jdbc:mysql://192.168.1.11:3306/restcomm + mysqlDriver + TRANSACTION_READ_COMMITTED + + 100 + 200 + + + root + myPWD + + + 100 + + + +---- + +* Once you have completed the 2 steps above, Restcomm Server1 and Server2 will  use the same Mysql database running on 192.168.1.11 diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/2-Restcomm-Servers-Using-a-Single-Mysql-Server.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/2-Restcomm-Servers-Using-a-Single-Mysql-Server.png new file mode 100644 index 0000000000..67d420352a Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/2-Restcomm-Servers-Using-a-Single-Mysql-Server.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Telscale-load-balancer-for-Restcomm.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Telscale-load-balancer-for-Restcomm.png new file mode 100644 index 0000000000..4b8a1ecc5b Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Telscale-load-balancer-for-Restcomm.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Two-Restcomm-Servers-Sharing-a-Single-RVD-Workspace-.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Two-Restcomm-Servers-Sharing-a-Single-RVD-Workspace-.png new file mode 100644 index 0000000000..63d973bc1e Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ha/images/Two-Restcomm-Servers-Sharing-a-Single-RVD-Workspace-.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/1.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/1.png new file mode 100644 index 0000000000..0733d2fcbc Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/1.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/10.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/10.png new file mode 100644 index 0000000000..b5d80fafec Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/10.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/13.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/13.png new file mode 100644 index 0000000000..e90a02877e Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/13.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/14.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/14.png new file mode 100644 index 0000000000..cf1ce8ac76 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/14.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/15.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/15.png new file mode 100644 index 0000000000..45a7ea9265 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/15.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/2.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/2.png new file mode 100644 index 0000000000..38e4c213e2 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/2.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/3.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/3.png new file mode 100644 index 0000000000..d07cfc09ee Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/3.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/4.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/4.png new file mode 100644 index 0000000000..c5bb4e5650 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/4.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/5.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/5.png new file mode 100644 index 0000000000..aadc48be59 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/5.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/6.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/6.png new file mode 100644 index 0000000000..4cef2e9997 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/6.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/7.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/7.png new file mode 100644 index 0000000000..d551a7b1b9 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/7.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/8.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/8.png new file mode 100644 index 0000000000..0669f0f7ba Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/8.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.27.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.27.png new file mode 100644 index 0000000000..29a6b60649 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.27.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.45.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.45.png new file mode 100644 index 0000000000..e609f214df Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/Screen-Shot-2016-02-04-at-14.14.45.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/olympus-1.jpg b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/olympus-1.jpg new file mode 100644 index 0000000000..456ae5b2f3 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/olympus-1.jpg differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-1.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-1.png new file mode 100644 index 0000000000..cb7f11d2b9 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-1.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-2.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-2.png new file mode 100644 index 0000000000..4b7afff3e4 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-2.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-3.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-3.png new file mode 100644 index 0000000000..c6172534be Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-3.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-4.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-4.png new file mode 100644 index 0000000000..b8e003c15f Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-VI-DID-4.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-login-page.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-login-page.png new file mode 100644 index 0000000000..137234eb13 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-login-page.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-pwd-reset.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-pwd-reset.png new file mode 100644 index 0000000000..109de7057c Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-pwd-reset.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo.jpg b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo.jpg new file mode 100644 index 0000000000..b2e5dcbcda Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo.jpg differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo2.jpg b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo2.jpg new file mode 100644 index 0000000000..e6153261e0 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo2.jpg differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo31.jpg b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo31.jpg new file mode 100644 index 0000000000..adcebb3df2 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo31.jpg differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo5.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo5.png new file mode 100644 index 0000000000..9ab65e7fb6 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/images/restcomm-smpp-nexmo5.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_ActAsProxy.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_ActAsProxy.adoc new file mode 100644 index 0000000000..b4c002bf3c --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_ActAsProxy.adoc @@ -0,0 +1,124 @@ +[[intro]] += Restcomm as a generic Proxy + +Restcomm can be configured to act as B2BUA and proxy out incoming calls (that didn't matched a registered application or a registered client) based on certain rules. + +On incoming call, the feature will be executed after Restcomm-Connect finish checking: + +1. Call to a registered Application/DID +2. Call to a registered Client + +Restcomm-Connect will use Dial SIP RCML to proxy the call to the destination which means that media server will be in the call path. + +== Configuration + +To enable this feature you will need to modify the **restcomm.xml** configuation file, and edit the **ims-authentication** section: + +[source,xml] +---- + + false + true + + + + + + + + + + + + + + + + + +---- + + +=== Options + +* `enabled` set to **true** to enable the feature +* `use-from-header` if set to **true**, From header will be used to determine the From URI. If set to **false** the Contact header will be used to determine the From URI. Default **true** (use From header) +* `proxy-rules` Define the rules to match incoming traffic. You can define as many rules as you need +** `from-uri` Define the **From URI** that will be used to match the incoming traffic +** `to-uri` Define the **To URI** which will be used to proxy out incoming traffic that matched the rule +** `proxy-to-username` (Optional) Username for proxy +** `proxy-to-password` (Optional) Password for proxy + + +When enabled, the feature will try to match incoming traffic from **from-uri** and if matched will proxy it to **to-uri** + +=== Example configuration + +Given + +* ClientA: **192.168.100.10:5060** +* Restcomm InstanceA: **192.168.100.11:5080** +* Restcomm InstanceB: **192.168.200.11:5080** + +The configuration should be: + +[source,xml] +---- + + true + true + + + 192.168.100.10:5060 + 192.168.200.11:5080 + + + + + + 192.168.200.11:5080 + 192.168.100.10:5060 + + + + + + +---- + + + +The first rule: +[source,xml] +---- + + 192.168.100.10:5060 + 192.168.200.11:5080 + + + + +---- + +Will match traffic from **192.168.100.10:5060** (**ClientA**) and will proxy out to **192.168.200.11:5080** (**Restcomm InstanceB**) + + + +The second rule: +[source,xml] +---- + + 192.168.200.11:5080 + 192.168.100.10:5060 + + + + +---- +Will match traffic from **192.168.200.11:5080** (**Restcomm InstanceB**) and will proxy out to **192.168.100.10:5060** (**ClientA**) + +== Call flows + +Following a call flow for how the feature is used + +image::images/RestcommB2BUA.png[Restcomm B2BUA] diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_IMS_GW.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_IMS_GW.adoc new file mode 100644 index 0000000000..3a78157a43 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/Restcomm_IMS_GW.adoc @@ -0,0 +1,52 @@ +[[intro]] += Restcomm as a WebRTC gateway to IMS + +The main aspect of this feature is to associate WebRTC clients with IMS core network, in other words to make WebRTC clients act as IMS core network clients. + +All signaling from WebRTC client should be sent toward IMS, and signaling from IMS should be passed to WebRTC clients. + +Restcomm will act as a WebRTC gateway to IMS core network. + +== Configuration + +To enable this feature you will need to modify the **restcomm.xml** configuation file, and edit the **ims-authentication** section: + +[source,xml] +---- + + true + ims.com + ims.com + 5060 + WebRTCGW__1@ + WebRTCGW/1.0 + ims + +---- + +== Call flows and examples + +=== 1. WebRTC client registration + +The registration of WebRTC clients is routed to IMS, and only when accepted by IMS it is stored in Restcomm-Connect database. The sequence diagram below illustrates IMS registration process. + +image::images/webrtc_client_registration.png[WebRTC client Registration] + + +=== 2. WebRTC client outgoing call + +The outgoing call from WebRTC client registered in IMS is routed to IMS. The sequence diagram below illustrates outgoing call flow. + +image::images/webrtc_client_outgoing_call.png[WebRTC client outgoing call to IMS core network] + +=== 3. WebRTC client incoming call + +The incoming call from IMS is passed to WebRTC client. The sequence diagram below illustrates incoming call flow. + +image::images/webrtc_incoming_call.png[WebRTC client incoming call] + +=== 4. WebRTC call hold flow + +The Restcomm-Connect handles call hold action and makes sure to pass hold indication to client and IMS. The sequence diagram below illustrates the call hold scenario. + +image::images/webrtc_call_hold.png[WebRTC call hold flow] diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/RestcommB2BUA.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/RestcommB2BUA.png new file mode 100644 index 0000000000..d03f0b15ca Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/RestcommB2BUA.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_call_hold.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_call_hold.png new file mode 100644 index 0000000000..dbbe19f585 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_call_hold.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_outgoing_call.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_outgoing_call.png new file mode 100644 index 0000000000..2a85f14a98 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_outgoing_call.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_registration.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_registration.png new file mode 100644 index 0000000000..34a80e37b8 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_client_registration.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_incoming_call.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_incoming_call.png new file mode 100644 index 0000000000..b682be523a Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/ims_b2bua/images/webrtc_incoming_call.png differ 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 new file mode 100644 index 0000000000..3a6aeff372 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/index.adoc @@ -0,0 +1,86 @@ += Restcomm Configuration + +If you don't use the hosted version of Restcomm, then you will need to install Restcomm in a local environment. The tutorials below will guide you on how to do that and install, configure and start Restcomm to fit your local environment + +=== Supported Operating System and Language +Please note that English is the only supported Linux Operating System Language. In most production deployment, most of our customers use the following English language Linux distribution : Red Hat Enterprise Linux and Ubuntu LTS + +== Basic Configuration Resources + +There is two different ways to install Restcomm Connect. Either through Docker or through binary. You will find below instructions for both + +=== Docker Installation and Start + +* <> + +=== Binary Installation and Start + +* <> +* <> +* <> +* <> + +=== Database Configuration + +* <> +* <> +* <> +* <> + +=== DID Configuration + +* <> +* <> +* <> +* <> +* <> + +== Advanced Configuration Resources + +=== Upgrade + +* <> +* <> + +=== Media + +* <> +* <> + +* <> + +=== Security + +* <> +* <> + +=== SMS + +* <> + +=== High Availability and Load Balancing + +* <> +* <> +* <> + +=== IMS GW - B2BUA + +* <> +* <> + +=== Amazon S3 Integration + +* <> + +=== Automatic Speech Recognition Integration + +* <> + +== DNS Provisioning Provider to create new domains under restcomm + +* <> + +== Contributor Resources + +* <> diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/s3/Restcomm_S3.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/s3/Restcomm_S3.adoc new file mode 100644 index 0000000000..7d2b0de52e --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/s3/Restcomm_S3.adoc @@ -0,0 +1,39 @@ +[[intro]] += Restcomm Amazon S3 Integration + +With Restcomm Amazon S3 Integration you can use Amazon S3 for recording storage. + +Either if you use Record verb or you use Dial with record, if the Amazon S3 integrations is enabled, the recording will be uploaded to Amazon S3 bucket you specified. + +== Configuration + +To enable Amazon S3 integration check instructions here: <<../Restcomm-Advanced Automatic Configuration Options.adoc#amazons3,Amazon S3 configuration>> + +== Advanced configuration + +You can configure how Restcomm will treat the Amazon S3 URL of the uploaded recording by changing the security level at restcomm.xml: + +[source,xml] +---- + + false + restcomm-recordings + + + + false + 10 + true + us-east-1 + secure + +---- + + +The Security level controls the details that the Recordings REST API will provide to the user and also how the user will access the wav file. + +1. **NONE**: Recordings REST API response, will contain the S3_URI with no credentials. Restcomm will fetch and serve recording to the user if the FILE_URI of the Recording is used +2. **REDIRECT**: Recordings REST API response will NOT contain the S3_URI. Restcomm will create redirect response and recording will be served by Amazon S3 if the FILE_URI of the Recording is used +3. **SECURE**: Recordings REST API response will NOT contain the S3_URI. Restcomm will fetch and serve recording to the user if the FILE_URI of the Recording is used + +Default value is **SECURE** diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo-footer.html b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo-footer.html new file mode 100644 index 0000000000..821e76513b --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo-footer.html @@ -0,0 +1,90 @@ + + + + + + + + + diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo.html b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo.html new file mode 100644 index 0000000000..2b11527c0f --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/docinfo.html @@ -0,0 +1,252 @@ + + + + Telestax | Real-Time Communication Unleashed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/index.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/index.adoc new file mode 100644 index 0000000000..a3ab43f7f8 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/index.adoc @@ -0,0 +1,37 @@ += Restcomm Organizations + +Purpose of this document is to share the design for implementing the functionality around Organizations in Restcomm + +== What is an Organization +A virtual Restcomm plateform provided to a customer on a unique custom domain. e.g. customer1.restcomm.com + +include::organizations/uml/component.adoc[] + +* True multitenacy for numbers and clients. SIP numbers/clients are unique to a particular organization and not the entire plateform. + +* Routing of Numbers so they don’t conflict under a given domain/organization but can exist under other domain/organizations. + +* Provide account holders with the ability to have a custom sub-domain mydomain.restcomm.com and/or mysubdomain.mydomain.restcomm.com + +* Whitelabeling: Provide the ability to have a customizable user experience for a service provider’s end customers (a skinnable dashboard and RVD, etc.) + +* Custom URL for API calls https://mydomain.restcomm.com/%E2%80%A6[https://mydomain.restcomm.com/…] + +* Sharding of organizations/domain for scale, SLA, performance + +* Consolidated billing for a given Organization + +== High Level Routing + +include::organizations/uml/routing.adoc[] + + +== SIP Routing + +include::organizations/uml/activitydiagram.adoc[] + + + +== Database +include::organizations/uml/datamodel.adoc[] + diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/activitydiagram.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/activitydiagram.adoc new file mode 100644 index 0000000000..9a79d69dec --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/activitydiagram.adoc @@ -0,0 +1,30 @@ +[plantuml, activitydiagram, png] +-- + +title Request Routing + +start +:Y@company.restcomm.com\nInitiate Call/Message\nX@company.restcomm.com; +if (X is a client?) then (yes) + if (Y.organization = X.organization ?) then (yes) + :Connect Y with X; + else (no) + :Reject Call (404); + :Send notification; + endif +else (no) + if (X is a SIP number ?) then (yes) + if (Y.organization = X.organization ?) then (yes) + :Connect Y with X; + else (no) + :Reject Call (404); + :Send notification; + endif + else (no) + :X is Provider Number!; + :Connect Y with X; + endif +endif + +stop +-- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/component.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/component.adoc new file mode 100644 index 0000000000..ddbf0c6c42 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/component.adoc @@ -0,0 +1,25 @@ +[plantuml, component, png] +-- +node "Restcomm" { +node "Organization1" { + [Org1-Accounts] + [Org1-Numbers] + [Org1-Clients] + [Org1-Applications] +} + +node "Organization2" { + [Org2-Accounts] + [Org2-Numbers] + [Org2-Clients] + [Org2-Applications] +} +} + interface org1.restcomm.com as org1 + interface org2.restcomm.com as org2 + +DNS -down- org1 +DNS -down- org2 +Organization1 -up- org1 +Organization2 -up- org2 +-- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/datamodel.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/datamodel.adoc new file mode 100644 index 0000000000..cf55b45f7b --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/datamodel.adoc @@ -0,0 +1,54 @@ +[plantuml, datamodel, png] +-- + +!define table(x) class x << (T,#FFAAAA) >> +!define primary_key(x) x +!define foreign_key(x) x +hide methods +hide stereotypes + +table(restcomm_organizations) { + +primary_key(sid) + domain_name [unique] + date_created + date_updated +} + +table(restcomm_accounts) { + +primary_key(sid) + email + type + status + ... + +foreign_key(organization_sid) +} + +table(restcomm_incoming_phone_numbers) { + +primary_key(sid) + +foreign_key(account_sid) + phone_number + ... + +foreign_key(organization_sid) +} + +table(restcomm_clients) { + +primary_key(sid) + client + ... + +foreign_key(account_sid) +} + +table(restcomm_registrations) { + +primary_key(sid) + user_name + ... + +foreign_key(organization_sid) +} + +restcomm_accounts "*" --- "1" restcomm_organizations +restcomm_incoming_phone_numbers "1" --- "1" restcomm_organizations +restcomm_incoming_phone_numbers "1" --- "1" restcomm_accounts +restcomm_clients "1" --- "1" restcomm_organizations +restcomm_clients "1" --- "1" restcomm_accounts +restcomm_registrations "1" --- "1" restcomm_organizations +-- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/routing.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/routing.adoc new file mode 100644 index 0000000000..bd707a7071 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/features/organizations/uml/routing.adoc @@ -0,0 +1,25 @@ +[plantuml, routing, png] +-- + +:HTTPS / SIP\n Traffic; +split + :organization1.restcomm.com; +split again + :organization2.restcomm.com; +split again + :organization3.restcomm.com; +split again + :organization4.restcomm.com; +end split +:DNS; +:Restcomm LoadBalancer; +split + :Restcomm node 1; +split again + :Restcomm node 2; +split again + :Restcomm node 3; +split again + :Restcomm node N; +end split +-- \ No newline at end of file diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/1.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/1.png new file mode 100644 index 0000000000..0733d2fcbc Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/1.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/10.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/10.png new file mode 100644 index 0000000000..b5d80fafec Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/10.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/13.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/13.png new file mode 100644 index 0000000000..e90a02877e Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/13.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/14.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/14.png new file mode 100644 index 0000000000..cf1ce8ac76 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/14.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/15.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/15.png new file mode 100644 index 0000000000..45a7ea9265 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/15.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/2.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/2.png new file mode 100644 index 0000000000..38e4c213e2 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/2.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/3.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/3.png new file mode 100644 index 0000000000..d07cfc09ee Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/3.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/4.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/4.png new file mode 100644 index 0000000000..c5bb4e5650 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/4.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/6.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/6.png new file mode 100644 index 0000000000..4cef2e9997 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/6.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/8.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/8.png new file mode 100644 index 0000000000..0669f0f7ba Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/8.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/bridge-the-gap.png b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/bridge-the-gap.png new file mode 100644 index 0000000000..594a5d9651 Binary files /dev/null and b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/images/bridge-the-gap.png differ diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/index.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/index.adoc new file mode 100644 index 0000000000..8eb2aa5dd2 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/index.adoc @@ -0,0 +1,23 @@ += RestComm Connect Documentation + +Restcomm-Connect is an API Exposure layer allowing Web developers to embed Communications as a Feature without having to know anything about telecommunications as can be seen below + +image::images/bridge-the-gap.png[bridgethegap,width=370,height=370,align="center"] + +You can read <> to learn more on how to build powerful apps or learn to master the platform. + +There is multiple ways to interact with Restcomm Connect to build applications + +* By using the <> to build applications easily with drag and drop without knowing anything about programming + +* The <> allows you to query meta-data about your account, phone numbers, calls, text messages, and recordings. You can also do some communications control like initiate outbound calls and send text messages. + +* The <> is a set of instructions you can use to tell Restcomm what to do when you receive an incoming call or SMS. + +* The <> allows you to embed Communications as a feature in your Web, iOS and Android Native Applications + +* The <> allows you to interact with your account, buy DIDs, configure your Restcomm Clients, check your logs and much more + +* The <> will help you in creating sample applications that cover common use cases in a variety of languages using the Restcomm API, RCML or Visual Designer. Download, test, and tweak for yourself. + +* The <> will help you in setting up Restcomm Connect on your own server or development environment to build powerful apps locally. diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/js/default.js b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/js/default.js new file mode 100644 index 0000000000..e96c8924b4 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/js/default.js @@ -0,0 +1,6554 @@ +var $j = jQuery.noConflict(); +var $scroll = 0; +var $window_width = $j(window).width(); +var $window_height = $j(window).height(); +var logo_height; +var menu_dropdown_height_set = false; +var sticky_amount = 0; +var content_menu_position; +var content_menu_top; +var content_menu_top_add = 0; +var src; +var next_image; +var prev_image; +var $top_header_height; + +var min_w = 1500; // minimum video width allowed +var video_width_original = 1280; // original video dimensions +var video_height_original = 720; +var vid_ratio = 1280/720; +var skrollr_slider; +var paspartu_width; +if(typeof paspartu_width_init == 'undefined'){ //check if variable is defined in default_dynamic.php (deafult_dynamic.js) + var paspartu_width_init = 0.02; +} + +$j(document).ready(function() { + "use strict"; + + if($j('header').hasClass('regular')){ + content_menu_top = 0; + } + if($j('header').hasClass('fixed_top_header')){ + content_menu_top = header_height; + } + if($j('header').hasClass('fixed')){ + content_menu_top = min_header_height_scroll; + } + if($j('header').hasClass('fixed_hiding')){ + content_menu_top = min_header_height_fixed_hidden + 40; //40 is top and bottom margin of logo + } + if($j('header').hasClass('stick') || $j('header').hasClass('stick_with_left_right_menu')){ + content_menu_top = 0; + } + if((!$j('header.page_header').hasClass('scroll_top')) && ($j('header.page_header').hasClass('has_top')) && ($j('header.page_header').hasClass('fixed'))){ + content_menu_top_add = 34; + } + if($j('body').hasClass('vertical_menu_enabled')){ + content_menu_top = 0; + content_menu_top_add = 0; + var min_header_height_sticky = 0; + } + + //check paspartu width depending on window size + paspartu_width = $window_width < 1024 ? 0.02 : paspartu_width_init; + + contentMinHeight(); + contentMinHeightWithPaspartu(); + setDropDownMenuPosition(); + initDropDownMenu(); + initVerticalMenu(); + initVerticalMobileMenu(); + initQodeSlider(); + initSideMenu(); + initPopupMenu(); + initMessageHeight(); + initToCounter(); + initCounter(); + if(!$j('.vertical_split_slider').length){ + initCountdown(); + } + initProgressBars(); + initListAnimation(); + initPieChart(); + initPieChartWithIcon(); + initServiceAnimation(); + initParallaxTitle(); + initSideAreaScroll(); + initVerticalAreaMenuScroll(); + loadMore(); + prettyPhoto(); + alterWPMLSwitcherHeaderBottom(); + initMobileMenu(); + initFlexSlider(); + fitVideo(); + fitAudio(); + initAccordion(); + initAccordionContentLink(); + initMessages(); + initProgressBarsIcon(); + initMoreFacts(); + placeholderReplace(); + backButtonShowHide(); + backToTop(); + initSteps(); + showGoogleMap(); + initProgressBarsVertical(); + initElementsAnimation(); + updateShoppingCart(); + initHashClick(); + initIconWithTextAnimation(); + initVideoBackground(); + initCheckSafariBrowser(); + initSearchButton(); + initCoverBoxes(); + createContentMenu(); + contentMenuScrollTo(); + createSelectContentMenu(); + initButtonHover(); + initSocialIconHover(); + initPageTitleAnimation(); + initIconShortcodeHover(); + initIconWithTextHover(); + parallaxLayers(); + + $j('.widget #searchform').mousedown(function(){$j(this).addClass('form_focus');}).focusout(function(){$j(this).removeClass('form_focus');}); + $scroll = $j(window).scrollTop(); + checkTitleToShowOrHide(); //this has to be after setting $scroll since function uses $scroll variable + checkVerticalMenuTransparency(); //this has to be after setting $scroll since function uses $scroll variable + + /* set header and content menu position and appearance on page load - START */ + if($j(window).width() > 1000){ + headerSize($scroll); + }else{ + logoSizeOnSmallScreens(); + } + + if($j(window).width() > 768){ + contentMenuPosition(); + } + contentMenuCheckLastSection(); + + $j('header:not(.stick_with_left_right_menu) .q_logo a').css('visibility','visible'); + /* set header and content menu position and appearance on page load - END */ + + initFullScreenTemplate(); + showHideVerticalMenu(); + initMasonryGallery(); + initLoadNextPostOnBottom(); +}); + +$j(window).load(function(){ + "use strict"; + + $j('.touch .main_menu li:has(div.second)').doubleTapToGo(); // load script to close menu on touch devices + initSmallImageBlogHeight(); + setDropDownMenuPosition(); + initDropDownMenu(); + initPortfolio(); + initPortfolioZIndex(); + initPortfolioSingleInfo(); + initTestimonials(); + initVideoBackgroundSize(); + initBlog(); + initBlogMasonryFullWidth(); + initQBlog(); + initPortfolioMasonry(); + initPortfolioMasonryFilter(); + initTabs(); + countClientsPerRow(); + animatedTextIconHeight(); + countAnimatedTextIconPerRow(); + initTitleAreaAnimation(); + setContentBottomMargin(); + footerWidth(); + if($j('nav.content_menu').length > 0){ + content_menu_position = $j('nav.content_menu').offset().top; + contentMenuPosition(); + } + contentMenuCheckLastSection(); + initQodeCarousel(); + initPortfolioSlider(); + initBlogSlider(); + initTabsActiveBorder(); + setActiveTabBorder(); + initImageHover(); + $j('header.stick_with_left_right_menu .q_logo a').css('visibility','visible'); + setMargingsForLeftAndRightMenu(); + initImageGallerySliderNoSpace(); + initVerticalSplitSlider(); + initParallax(); //has to be here on last place since some function is interfering with parallax + initQodeElementAnimationSkrollr(); + setTimeout(function(){ + checkAnchorOnScroll(); + checkAnchorOnLoad(); // it has to be after content top margin initialization to know where to scroll + checkHeaderStyleOnScroll(); //moved to window load because sections are not fully initialized on dom ready and calculations are wrong + if($j('.no-touch .carousel').length){skrollr_slider.refresh();} //in order to reload rest of scroll animation on same page after page loads + },700); //timeout is set because of some function that interferes with calculating +}); + +$j(window).scroll(function() { + "use strict"; + + $scroll = $j(window).scrollTop(); + + if($j(window).width() > 1000){ + headerSize($scroll); + } + + if($j(window).width() > 768){ + contentMenuPosition(); + } + contentMenuCheckLastSection(); + checkVerticalMenuTransparency(); + + $j('.touch .drop_down > ul > li').mouseleave(); + $j('.touch .drop_down > ul > li').blur(); +}); + +$j(window).resize(function() { + "use strict"; + + $window_width = $j(window).width(); + $window_height = $j(window).height(); + + //check paspartu width depending on window size + paspartu_width = $window_width < 1024 ? 0.02 : paspartu_width_init; + + if($j(window).width() > 1000){ + headerSize($scroll); + }else{ + logoSizeOnSmallScreens(); + } + initMessageHeight(); + initTestimonials(); + fitAudio(); + initSmallImageBlogHeight(); + initBlog(); + initBlogMasonryFullWidth(); + initQBlog(); + animatedTextIconHeight(); + countAnimatedTextIconPerRow(); + initVideoBackgroundSize(); + countClientsPerRow(); + setContentBottomMargin(); + footerWidth(); + calculateHeights(); + $j('.vertical_split_slider').height($window_height); //used for vertical split slider holder + initMasonryGallery(); + contentMinHeight(); + contentMinHeightWithPaspartu(); +}); + +/* +** Calculating header size on page load and page scroll +*/ +var sticky_animate; +function headerSize($scroll){ + "use strict"; + + if(($j('header.page_header').hasClass('scroll_top')) && ($j('header.page_header').hasClass('has_top')) && + ($j('header.page_header').hasClass('fixed') || $j('header.page_header').hasClass('fixed_hiding'))){ + if($scroll >= 0 && $scroll <= 34){ + $j('header.page_header').css('top',-$scroll); + $j('header.page_header').css('margin-top',0); + $j('.header_top').show(); + }else if($scroll > 34){ + $j('header.page_header').css('top','-34px'); + $j('header.page_header').css('margin-top',34); + $j('.header_top').hide(); + } + } + + //is scroll amount for sticky set on page? + if(typeof page_scroll_amount_for_sticky !== 'undefined') { + sticky_amount = page_scroll_amount_for_sticky; + } + + //do we have slider on the page? + else if($j('.carousel.full_screen').length) { + sticky_amount = $j('.carousel').height(); + } + + //take value from theme options + else { + sticky_amount = scroll_amount_for_sticky; + } + + if($j('header').hasClass('regular')){ +// $j('header .drop_down .second').css('top', header_height + header_bottom_border_weight +'px'); + if(header_height - logo_height >= 10){ + $j('.q_logo a').height(logo_height); + }else{ + $j('.q_logo a').height(header_height - 10); + } + $j('.q_logo a img').css('height','100%'); + } + + if($j('header.page_header').hasClass('fixed')){ + if($j('header.page_header').hasClass('scroll_top')){ + $top_header_height = 34; + }else{ + $top_header_height = 0; + } + + if((header_height - $scroll + $top_header_height >= min_header_height_scroll) && ($scroll >= $top_header_height)){ + $j('header.page_header').removeClass('scrolled'); + $j('header:not(.centered_logo.centered_logo_animate) nav.main_menu > ul > li > a').css('line-height', header_height - $scroll + $top_header_height+'px'); +// $j('header .drop_down .second').css('top', header_height + header_bottom_border_weight - ($scroll + $top_header_height)/8+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .side_menu_button').css('height', header_height - $scroll + $top_header_height+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .shopping_cart_inner').css('height', header_height - $scroll + $top_header_height+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .logo_wrapper').css('height', header_height - $scroll + $top_header_height +'px'); + if(header_height - logo_height > 0){ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', logo_height +'px'); + }else{ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', (header_height - $scroll + $top_header_height - 10) +'px'); + } + + }else if($scroll < $top_header_height){ + $j('header.page_header').removeClass('scrolled'); + $j('header:not(.centered_logo.centered_logo_animate) nav.main_menu > ul > li > a').css('line-height', header_height+'px'); +// $j('header .drop_down .second').css('top', header_height + header_bottom_border_weight +'px'); + $j('header:not(.centered_logo.centered_logo_animate) .side_menu_button').css('height', header_height+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .shopping_cart_inner').css('height', header_height+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .logo_wrapper').css('height', header_height+'px'); + if(header_height - logo_height > 0){ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', logo_height +'px'); + }else{ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', (header_height-10)+'px'); + } + + }else if((header_height - $scroll + $top_header_height) < min_header_height_scroll){ + $j('header.page_header').addClass('scrolled'); + $j('header:not(.centered_logo.centered_logo_animate) nav.main_menu > ul > li > a').css('line-height', min_header_height_scroll+'px'); +// $j('header .drop_down .second').css('top', min_header_height_scroll + header_bottom_border_weight +'px'); + $j('header:not(.centered_logo.centered_logo_animate) .side_menu_button').css('height', min_header_height_scroll+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .shopping_cart_inner').css('height', min_header_height_scroll+'px'); + $j('header:not(.centered_logo.centered_logo_animate) .logo_wrapper').css('height', min_header_height_scroll+'px'); + if(min_header_height_scroll - logo_height > 0){ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', logo_height +'px'); + }else{ + $j('header:not(.centered_logo.centered_logo_animate) .q_logo a').css('height', (min_header_height_scroll-10)+'px'); + } + } + + // logo part - start // + + if($j('header.page_header').hasClass('centered_logo') && $j('header.page_header').hasClass('centered_logo_animate')){ + if((header_height - $scroll + $top_header_height < logo_height) && (header_height - $scroll + $top_header_height >= min_header_height_scroll) && (logo_height > min_header_height_scroll - 10) && ($scroll >= $top_header_height)){ + $j('.q_logo a').height(header_height - $scroll + $top_header_height - 10); + }else if((header_height - $scroll + $top_header_height < logo_height) && (header_height - $scroll + $top_header_height >= min_header_height_scroll) && (logo_height > min_header_height_scroll - 10) && ($scroll < $top_header_height)){ + $j('.q_logo a').height(header_height - 10); + }else if((header_height - $scroll + $top_header_height < logo_height) && (header_height - $scroll + $top_header_height < min_header_height_scroll) && (logo_height > min_header_height_scroll - 10)){ + $j('.q_logo a').height(min_header_height_scroll - 10); + }else if((header_height - $scroll + $top_header_height < logo_height) && (header_height - $scroll + $top_header_height < min_header_height_scroll) && (logo_height < min_header_height_scroll - 10)){ + $j('.q_logo a').height(logo_height); + }else if(($scroll + $top_header_height === 0) && (logo_height > header_height - 10)){ + $j('.q_logo a').height(logo_height); + }else{ + $j('.q_logo a').height(logo_height); + } + }else if($j('header.page_header').hasClass('centered_logo')) { + $j('.q_logo a').height(logo_height); + $j('.q_logo img').height('auto'); + }else{ + $j('.q_logo img').height('100%'); + } + // logo part - end // + + } + + if($j('header.page_header').hasClass('fixed_hiding')){ + + if($scroll < scroll_amount_for_fixed_hiding){ + $j('header.page_header').removeClass('scrolled'); + }else{ + $j('header.page_header').addClass('scrolled'); + } + + $j('.q_logo a').height(logo_height/2); //because of retina displays + $j('.q_logo img').height('100%'); + } + + if($j('header.page_header').hasClass('stick') || $j('header.page_header').hasClass('stick_with_left_right_menu')){ + if($scroll > sticky_amount){ + if(!$j('header.page_header').hasClass('sticky')){ + if($j('header.page_header').hasClass('has_top')){ + $top_header_height = 34; + }else{ + $top_header_height = 0; + } + var padding_top = $j('header.page_header').hasClass('centered_logo') ? $j('header.page_header').height() : header_height + $top_header_height; + if($j('header.page_header').hasClass('menu_bottom')){ + padding_top = header_height + 60; //60 is menu height for Sticky Advance header type + } + $j('header.page_header').addClass('sticky'); + $j('.content').css('padding-top',padding_top); + + window.clearTimeout(sticky_animate); + sticky_animate = window.setTimeout(function(){$j('header.page_header').addClass('sticky_animate');},100); + + + if(min_header_height_sticky - logo_height >= 10){ + $j('.q_logo a').height(logo_height); + }else{ + $j('.q_logo a').height(min_header_height_sticky - 10); + } + + if($j('header.page_header').hasClass('menu_bottom')){ + initDropDownMenu(); //recalculate dropdown menu position + } + } + + // logo part - start // + if(min_header_height_sticky - logo_height >= 10){ + $j('.q_logo a').height(logo_height); + }else{ + $j('.q_logo a').height(min_header_height_sticky - 10); + } + // logo part - end // + }else{ + if($j('header.page_header').hasClass('sticky')){ + $j('header').removeClass('sticky_animate'); + $j('header').removeClass('sticky'); + $j('.content').css('padding-top','0px'); + + if($j('header.page_header').hasClass('menu_bottom')){ + initDropDownMenu(); //recalculate dropdown menu position + } + } + + setMargingsForLeftAndRightMenu(); //need to set margins here since on sticky menu, logo is not visible on left/right logo + + // logo part - start // + if(!$j('header.page_header').hasClass('centered_logo')){ + if(header_height - logo_height >= 10){ + $j('.q_logo a').height(logo_height); + }else{ + $j('.q_logo a').height(header_height - 10); + } + }else{ + $j('.q_logo a').height(logo_height); + $j('.q_logo img').height('auto'); + } + $j('.q_logo a img').css('height','100%'); + // logo part - end // + } + } +} + +function setMargingsForLeftAndRightMenu(){ + "use strict"; + + if($j('header.page_header').hasClass('stick_with_left_right_menu') && !$j('header.page_header').hasClass('left_right_margin_set')){ + var logo_width = $j('.q_logo a img').width()/2; + if($scroll == 0 && logo_width != 0){ + $j('header.page_header').addClass('left_right_margin_set'); + } + $j('.logo_wrapper').width(logo_width*2); + $j('nav.main_menu.left_side > ul > li:last-child').css('margin-right',logo_width); + $j('nav.main_menu.right_side > ul > li:first-child').css('margin-left',logo_width); + + $j('.rtl nav.main_menu.left_side > ul > li:first-child').css('margin-right',logo_width); // add for rtl + $j('.rtl nav.main_menu.left_side > ul > li:last-child').css('margin-right',0); // add for rtl + $j('.rtl nav.main_menu.right_side > ul > li:last-child').css('margin-left',logo_width); // add for rtl + $j('.rtl nav.main_menu.right_side > ul > li:first-child').css('margin-left',0); // add for rtl + } +} + +/* +** Calculating logo size on smaller screens +*/ +function logoSizeOnSmallScreens(){ + "use strict"; + // 100 is height of header on small screens + + if((100 - 20 < logo_height)){ + $j('.q_logo a').height(100 - 20); + }else{ + $j('.q_logo a').height(logo_height); + } + $j('.q_logo a img').css('height','100%'); + + $j('header.page_header').removeClass('sticky_animate sticky'); + $j('.content').css('padding-top','0px'); + +} + +/* + ** Calculating minimal height for content + */ +function contentMinHeight(){ + "use strict"; + + if($j('header .header_bottom').length || $j('header .bottom_header').length){ + if($j('header .header_bottom').length){ var headerColorString = $j('header .header_bottom').css('background-color'); } + if($j('header .bottom_header').length){ var headerColorString = $j('header .bottom_header').css('background-color'); } + var headerTransparency = headerColorString.substring(headerColorString.indexOf('(') + 1, headerColorString.lastIndexOf(')')).split(/,\s*/)[3]; + var haeder_add = headerTransparency == undefined && !$j('header.page_header').hasClass('transparent') ? $j('header.page_header').height() : 0; + /*$j('body .content').css('min-height',$window_height - haeder_add - $j('footer:not(.uncover)').height());*/ + } +} + +/* + ** Calculating minimal height for content when paspartu is enabled + */ + +function contentMinHeightWithPaspartu(){ + "use strict"; + + if ($j('.paspartu_enabled').length) { + var content_height; + var paspartu_final_width_px = 0; + var paspartu_width_px = $window_width*paspartu_width; + var footer_height = $j('footer').height(); + + if ($j('.disable_footer').length){ + footer_height = 0; + } + + if ($j('.vertical_menu_enabled').length){ + if ($j('.paspartu_top').length && $j('.paspartu_middle_inner').length){ + paspartu_final_width_px += paspartu_width_px; + } + } + else { + if ($j('.paspartu_top').length){ + paspartu_final_width_px += paspartu_width_px; + } + } + if ($j('.paspartu_bottom').length || !$j('.disable_bottom_paspartu').length){ + paspartu_final_width_px += paspartu_width_px; + } + + if ($j('.vertical_menu_enabled').length){ + content_height = $window_height - paspartu_final_width_px - footer_height; + } + else { + if($j('header .header_bottom').length){ var headerColorString = $j('header .header_bottom').css('background-color'); } + if($j('header .bottom_header').length){ var headerColorString = $j('header .bottom_header').css('background-color'); } + var headerTransparency = headerColorString.substring(headerColorString.indexOf('(') + 1, headerColorString.lastIndexOf(')')).split(/,\s*/)[3]; + var header_height = headerTransparency == undefined && !$j('header.page_header').hasClass('transparent') ? $j('header.page_header').height() : 0; + content_height = $window_height - header_height - paspartu_final_width_px - footer_height; + } + + /*if($j('.content').length){ + $j('.content').css('min-height',content_height); + }*/ + } +} + +/* +** Initialize Qode Slider +*/ +var default_header_style; +function initQodeSlider(){ + "use strict"; + + var image_regex = /url\(["']?([^'")]+)['"]?\)/; + default_header_style = ""; + if($j('header.page_header').hasClass('light')){ default_header_style = 'light';} + if($j('header.page_header').hasClass('dark')){ default_header_style = 'dark';} + + if($j('.carousel').length){ + + var matrixArray = { zoom_center : '1.2, 0, 0, 1.2, 0, 0', zoom_top_left: '1.2, 0, 0, 1.2, -150, -150', zoom_top_right : '1.2, 0, 0, 1.2, 150, -150', zoom_bottom_left: '1.2, 0, 0, 1.2, -150, 150', zoom_bottom_right: '1.2, 0, 0, 1.2, 150, 150'}; + + // Function for translating image in slide - START // + (function ($) { + // + // regular expression for parsing out the matrix + // components from the matrix string + // + var matrixRE = /\([0-9epx\.\, \t\-]+/gi; + + // + // parses a matrix string of the form + // "matrix(n1,n2,n3,n4,n5,n6)" and + // returns an array with the matrix + // components + // + var parseMatrix = function (val) { + return val.match(matrixRE)[0].substr(1). + split(",").map(function (s) { + return parseFloat(s); + }); + }; + + // + // transform css property names with vendor prefixes; + // the plugin will check for values in the order the + // names are listed here and return as soon as there + // is a value; so listing the W3 std name for the + // transform results in that being used if its available + // + var transformPropNames = [ + "transform", + "-webkit-transform" + ]; + + var getTransformMatrix = function (el) { + // + // iterate through the css3 identifiers till we + // hit one that yields a value + // + var matrix = null; + transformPropNames.some(function (prop) { + matrix = el.css(prop); + return (matrix !== null && matrix !== ""); + }); + + // + // if "none" then we supplant it with an identity matrix so + // that our parsing code below doesn't break + // + matrix = (!matrix || matrix === "none") ? + "matrix(1,0,0,1,0,0)" : matrix; + return parseMatrix(matrix); + }; + + // + // set the given matrix transform on the element; note that we + // apply the css transforms in reverse order of how its given + // in "transformPropName" to ensure that the std compliant prop + // name shows up last + // + var setTransformMatrix = function (el, matrix) { + var m = "matrix(" + matrix.join(",") + ")"; + for (var i = transformPropNames.length - 1; i >= 0; --i) { + el.css(transformPropNames[i], m + ' rotate(0.01deg)'); + } + }; + + // + // interpolates a value between a range given a percent + // + var interpolate = function (from, to, percent) { + return from + ((to - from) * (percent / 100)); + }; + + $.fn.transformAnimate = function (opt) { + // + // extend the options passed in by caller + // + var options = { + transform: "matrix(1,0,0,1,0,0)" + }; + $.extend(options, opt); + + // + // initialize our custom property on the element + // to track animation progress + // + this.css("percentAnim", 0); + + // + // supplant "options.step" if it exists with our own + // routine + // + var sourceTransform = getTransformMatrix(this); + var targetTransform = parseMatrix(options.transform); + options.step = function (percentAnim, fx) { + // + // compute the interpolated transform matrix for + // the current animation progress + // + var $this = $(this); + var matrix = sourceTransform.map(function (c, i) { + return interpolate(c, targetTransform[i], + percentAnim); + }); + + // + // apply the new matrix + // + setTransformMatrix($this, matrix); + + // + // invoke caller's version of "step" if one + // was supplied; + // + if (opt.step) { + opt.step.apply(this, [matrix, fx]); + } + }; + + // + // animate! + // + return this.stop().animate({ percentAnim: 100 }, options); + }; + })(jQuery); + // Function for translating image in slide - END // + + $j('.carousel').each(function(){ + var $this = $j(this); + var mobile_header; + + var mobile_header = $j(window).width() < 1000 ? $j('header.page_header').height() : 0; + var header_height_add_for_paspartu = $window_width > 1000 && !$j('header.page_header').hasClass('transparent') && $j('body.paspartu_on_top_fixed').length == 0 ? $j('header.page_header').height() : 0; + var paspartu_amount_with_top = $j('.paspartu_outer:not(.disable_top_paspartu)').length > 0 ? Math.round($window_width*paspartu_width + header_height_add_for_paspartu) : 0; + var paspartu_amount_with_bottom = $j('.paspartu_outer.paspartu_on_bottom_slider').length > 0 ? Math.round($window_width*paspartu_width) : 0; + var slider_graphic_coefficient; + var slider_title_coefficient; + var slider_subtitle_coefficient; + var slider_text_coefficient; + var slider_button_coefficient; + + var responsive_breakpoint_set = [1300,1000,768]; + if($this.hasClass('advanced_responsiveness')){ + responsive_breakpoint_set = [1600,1200,900,650,500,320]; + if($this.data('q_responsive_breakpoints')){ + if($this.data('q_responsive_breakpoints') == 'set2'){ + responsive_breakpoint_set = [1600,1300,1000,768,567,320]; + } + } + + var coefficients_graphic_array = $this.data('q_responsive_graphic_coefficients').split(','); + var coefficients_title_array = $this.data('q_responsive_title_coefficients').split(','); + var coefficients_subtitle_array = $this.data('q_responsive_subtitle_coefficients').split(','); + var coefficients_text_array = $this.data('q_responsive_text_coefficients').split(','); + var coefficients_button_array = $this.data('q_responsive_button_coefficients').split(','); + } + + //calculate heights for slider holder and slide item, depending on size, but only if slider is set to be responsive and not full screen + function setSliderHeight($this, $def_height){ + var slider_height = $def_height; + + if($this.hasClass('advanced_responsiveness')){ + //advanced responsiveness + if($window_width > responsive_breakpoint_set[0]){ + slider_height = $def_height; + }else if($window_width > responsive_breakpoint_set[1]){ + slider_height = $def_height * 0.75; + }else if($window_width > responsive_breakpoint_set[2]){ + slider_height = $def_height * 0.6; + }else if($window_width > responsive_breakpoint_set[3]){ + slider_height = $def_height * 0.55; + }else if($window_width <= responsive_breakpoint_set[3]){ + slider_height = $def_height * 0.45; + } + }else{ + //old way responsiveness + if($window_width > responsive_breakpoint_set[0]){ + slider_height = $def_height; + }else if($window_width > responsive_breakpoint_set[1]){ + slider_height = $def_height * 0.8; + }else if($window_width > responsive_breakpoint_set[2]){ + slider_height = $def_height * 0.7; + }else if($window_width <= responsive_breakpoint_set[2]){ + slider_height = $def_height * 1; + } + } + + $this.css({'height': (slider_height) + 'px'}); + $this.find('.qode_slider_preloader').css({'height': (slider_height) + 'px'}); + $this.find('.qode_slider_preloader .ajax_loader').css({'display': 'block'}); + $this.find('.item').css({'height': (slider_height) + 'px'}); + } + + function resetSliderHeight($def_height){ + $this.css({'height': ($def_height) + 'px'}); + $this.find('.qode_slider_preloader').css({'height': ($def_height) + 'px'}); + $this.find('.qode_slider_preloader .ajax_loader').css({'display': 'block'}); + $this.find('.item').css({'height': ($def_height) + 'px'}); + } + + function setSliderInitialElementsSize($item,i){ + + window["slider_graphic_width_" + i] = []; + window["slider_graphic_height_" + i] = []; + window["slider_svg_width_" + i] = []; + window["slider_svg_height_" + i] = []; + window["slider_title_" + i] = []; + window["slider_subtitle_" + i] = []; + window["slider_text_" + i] = []; + window["slider_button1_" + i] = []; + window["slider_button2_" + i] = []; + window["slider_separator_" + i] = []; + + //graphic size + window["slider_graphic_width_" + i].push(parseFloat($item.find('.thumb img').data("width"))); + window["slider_graphic_height_" + i].push(parseFloat($item.find('.thumb img').data("height"))); + window["slider_svg_width_" + i].push(parseFloat($item.find('.qode_slide-svg-holder svg').attr("width"))); + window["slider_svg_height_" + i].push(parseFloat($item.find('.qode_slide-svg-holder svg').attr("height"))); + + // font-size (0) + window["slider_title_" + i].push(parseFloat($item.find('.q_slide_title').css("font-size"))); + window["slider_subtitle_" + i].push(parseFloat($item.find('.q_slide_subtitle').css("font-size"))); + window["slider_text_" + i].push(parseFloat($item.find('.q_slide_text').css("font-size"))); + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("font-size"))); + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("font-size"))); + + // line-height (1) + window["slider_title_" + i].push(parseFloat($item.find('.q_slide_title').css("line-height"))); + window["slider_subtitle_" + i].push(parseFloat($item.find('.q_slide_subtitle').css("line-height"))); + window["slider_text_" + i].push(parseFloat($item.find('.q_slide_text').css("line-height"))); + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("line-height"))); + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("line-height"))); + + // letter-spacing (2) + window["slider_title_" + i].push(parseFloat($item.find('.q_slide_title').css("letter-spacing"))); + window["slider_subtitle_" + i].push(parseFloat($item.find('.q_slide_subtitle').css("letter-spacing"))); + window["slider_text_" + i].push(parseFloat($item.find('.q_slide_text').css("letter-spacing"))); + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("letter-spacing"))); + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("letter-spacing"))); + + // margin-bottom (3) + window["slider_title_" + i].push(parseFloat($item.find('.q_slide_title').css("margin-bottom"))); + window["slider_subtitle_" + i].push(parseFloat($item.find('.q_slide_subtitle').css("margin-bottom"))); + + // slider_button height(3), width(4), padding(5) + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("height"))); + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("height"))); + if(parseFloat($item.find('.qbutton:eq(0)').css("width")) != 0){ + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("width"))); + }else{ + window["slider_button1_" + i].push(0); + } + if(parseFloat($item.find('.qbutton:eq(1)').css("width")) != 0){ + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("width"))); + }else{ + window["slider_button2_" + i].push(0); + } + window["slider_button1_" + i].push(parseFloat($item.find('.qbutton:eq(0)').css("padding-left"))); + window["slider_button2_" + i].push(parseFloat($item.find('.qbutton:eq(1)').css("padding-left"))); + + // margin separator, margin top(0), margin bottom(1) + window["slider_separator_" + i].push(parseFloat($item.find('.separator').css("margin-top"))); + window["slider_separator_" + i].push(parseFloat($item.find('.separator').css("margin-bottom"))); + + } + + //calculate size for slider title, subtitle and text, depending on window size + function setSliderElementsSize($item,i){ + if($window_width > responsive_breakpoint_set[0]) { + slider_graphic_coefficient = coefficients_graphic_array[0]; + slider_title_coefficient = coefficients_title_array[0]; + slider_subtitle_coefficient = coefficients_subtitle_array[0]; + slider_text_coefficient = coefficients_text_array[0]; + slider_button_coefficient = coefficients_button_array[0]; + }else if($window_width > responsive_breakpoint_set[1]){ + slider_graphic_coefficient = coefficients_graphic_array[1]; + slider_title_coefficient = coefficients_title_array[1]; + slider_subtitle_coefficient = coefficients_subtitle_array[1]; + slider_text_coefficient = coefficients_text_array[1]; + slider_button_coefficient = coefficients_button_array[1]; + }else if($window_width > responsive_breakpoint_set[2]){ + slider_graphic_coefficient = coefficients_graphic_array[2]; + slider_title_coefficient = coefficients_title_array[2]; + slider_subtitle_coefficient = coefficients_subtitle_array[2]; + slider_text_coefficient = coefficients_text_array[2]; + slider_button_coefficient = coefficients_button_array[2]; + }else if($window_width > responsive_breakpoint_set[3]){ + slider_graphic_coefficient = coefficients_graphic_array[3]; + slider_title_coefficient = coefficients_title_array[3]; + slider_subtitle_coefficient = coefficients_subtitle_array[3]; + slider_text_coefficient = coefficients_text_array[3]; + slider_button_coefficient = coefficients_button_array[3]; + }else if ($window_width > responsive_breakpoint_set[4]) { + slider_graphic_coefficient = coefficients_graphic_array[4]; + slider_title_coefficient = coefficients_title_array[4]; + slider_subtitle_coefficient = coefficients_subtitle_array[4]; + slider_text_coefficient = coefficients_text_array[4]; + slider_button_coefficient = coefficients_button_array[4]; + }else if ($window_width > responsive_breakpoint_set[5]){ + slider_graphic_coefficient = coefficients_graphic_array[5]; + slider_title_coefficient = coefficients_title_array[5]; + slider_subtitle_coefficient = coefficients_subtitle_array[5]; + slider_text_coefficient = coefficients_text_array[5]; + slider_button_coefficient = coefficients_button_array[5]; + } + else{ + slider_graphic_coefficient = coefficients_graphic_array[6]; + slider_title_coefficient = coefficients_title_array[6]; + slider_subtitle_coefficient = coefficients_subtitle_array[6]; + slider_text_coefficient = coefficients_text_array[6]; + slider_button_coefficient = coefficients_button_array[6]; + } + + // letter-spacing decrease quicker + var slider_title_coefficient_letter_spacing = slider_title_coefficient; + var slider_subtitle_coefficient_letter_spacing = slider_subtitle_coefficient; + var slider_text_coefficient_letter_spacing = slider_text_coefficient; + if($window_width <= responsive_breakpoint_set[0]) { + slider_title_coefficient_letter_spacing = slider_title_coefficient/2; + slider_subtitle_coefficient_letter_spacing = slider_subtitle_coefficient/2; + slider_text_coefficient_letter_spacing = slider_text_coefficient/2; + } + + $item.find('.thumb').css({"width": Math.round(window["slider_graphic_width_" + i][0]*slider_graphic_coefficient) + 'px'}).css({"height": Math.round(window["slider_graphic_height_" + i][0]*slider_graphic_coefficient) + 'px'}); + $item.find('.qode_slide-svg-holder svg').css({"width": Math.round(window["slider_svg_width_" + i][0]*slider_graphic_coefficient) + 'px'}).css({"height": Math.round(window["slider_svg_height_" + i][0]*slider_graphic_coefficient) + 'px'}); + + $item.find('.q_slide_title').css({"font-size": Math.round(window["slider_title_" + i][0]*slider_title_coefficient) + 'px'}); + $item.find('.q_slide_title').css({"line-height": Math.round(window["slider_title_" + i][1]*slider_title_coefficient) + 'px'}); + $item.find('.q_slide_title').css({"letter-spacing": Math.round(window["slider_title_" + i][2]*slider_title_coefficient_letter_spacing) + 'px'}); + $item.find('.q_slide_title').css({"margin-bottom": Math.round(window["slider_title_" + i][3]*slider_title_coefficient) + 'px'}); + + $item.find('.q_slide_subtitle').css({"font-size": Math.round(window["slider_subtitle_" + i][0]*slider_subtitle_coefficient) + 'px'}); + $item.find('.q_slide_subtitle').css({"line-height": Math.round(window["slider_subtitle_" + i][1]*slider_subtitle_coefficient) + 'px'}); + $item.find('.q_slide_subtitle').css({"letter-spacing": Math.round(window["slider_subtitle_" + i][2]*slider_subtitle_coefficient_letter_spacing) + 'px'}); + $item.find('.q_slide_subtitle').css({"margin-bottom": Math.round(window["slider_subtitle_" + i][3]*slider_subtitle_coefficient) + 'px'}); + + $item.find('.q_slide_text').css({"font-size": Math.round(window["slider_text_" + i][0]*slider_text_coefficient) + 'px'}); + $item.find('.q_slide_text').css({"line-height": Math.round(window["slider_text_" + i][1]*slider_text_coefficient) + 'px'}); + $item.find('.q_slide_text').css({"letter-spacing": Math.round(window["slider_text_" + i][2]*slider_text_coefficient_letter_spacing) + 'px'}); + + $item.find('.qbutton:eq(0)').css({"font-size": Math.round(window["slider_button1_" + i][0]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"font-size": Math.round(window["slider_button2_" + i][0]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(0)').css({"line-height": Math.round(window["slider_button1_" + i][1]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"line-height": Math.round(window["slider_button2_" + i][1]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(0)').css({"letter-spacing": Math.round(window["slider_button1_" + i][2]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"letter-spacing": Math.round(window["slider_button2_" + i][2]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(0)').css({"height": Math.round(window["slider_button1_" + i][3]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"height": Math.round(window["slider_button2_" + i][3]*slider_button_coefficient) + 'px'}); + if(window["slider_button1_" + i][4] != 0) { + $item.find('.qbutton:eq(0)').css({"width": Math.round(window["slider_button1_" + i][4]*slider_button_coefficient) + 'px'}); + }else{ + $item.find('.qbutton:eq(0)').css({"width": 'auto'}); + } + if(window["slider_button2_" + i][4] != 0) { + $item.find('.qbutton:eq(1)').css({"width": Math.round(window["slider_button2_" + i][4]*slider_button_coefficient) + 'px'}); + }else{ + $item.find('.qbutton:eq(1)').css({"width": 'auto'}); + } + $item.find('.qbutton:eq(0)').css({"padding-left": Math.round(window["slider_button1_" + i][5]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"padding-left": Math.round(window["slider_button2_" + i][5]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(0)').css({"padding-right": Math.round(window["slider_button1_" + i][5]*slider_button_coefficient) + 'px'}); + $item.find('.qbutton:eq(1)').css({"padding-right": Math.round(window["slider_button2_" + i][5]*slider_button_coefficient) + 'px'}); + + $item.find('.separator').css({"margin-top": Math.round(window["slider_separator_" + i][0]*slider_title_coefficient) + 'px'}); + $item.find('.separator').css({"margin-bottom": Math.round(window["slider_separator_" + i][1]*slider_title_coefficient) + 'px'}); + + } + + function resetSliderElementsSize($item,i){ + $item.find('.thumb').css({"width": Math.round(window["slider_graphic_width_" + i][0]) + 'px'}).css({"height": Math.round(window["slider_graphic_height_" + i][0]) + 'px'}); + $item.find('.qode_slide-svg-holder svg').css({"width": Math.round(window["slider_svg_width_" + i][0]) + 'px'}).css({"height": Math.round(window["slider_svg_height_" + i][0]) + 'px'}); + + $item.find('.q_slide_title').css({"font-size": Math.round(window["slider_title_" + i][0]) + 'px'}); + $item.find('.q_slide_title').css({"line-height": Math.round(window["slider_title_" + i][1]) + 'px'}); + $item.find('.q_slide_title').css({"letter-spacing": Math.round(window["slider_title_" + i][2]) + 'px'}); + $item.find('.q_slide_title').css({"margin-bottom": Math.round(window["slider_title_" + i][3]) + 'px'}); + + $item.find('.q_slide_subtitle').css({"font-size": Math.round(window["slider_subtitle_" + i][0]) + 'px'}); + $item.find('.q_slide_subtitle').css({"line-height": Math.round(window["slider_subtitle_" + i][1]) + 'px'}); + $item.find('.q_slide_subtitle').css({"letter-spacing": Math.round(window["slider_subtitle_" + i][2]) + 'px'}); + $item.find('.q_slide_subtitle').css({"margin-bottom": Math.round(window["slider_subtitle_" + i][3]) + 'px'}); + + $item.find('.q_slide_text').css({"font-size": Math.round(window["slider_text_" + i][0]) + 'px'}); + $item.find('.q_slide_text').css({"line-height": Math.round(window["slider_text_" + i][1]) + 'px'}); + $item.find('.q_slide_text').css({"letter-spacing": Math.round(window["slider_text_" + i][2]) + 'px'}); + + $item.find('.qbutton:eq(0)').css({"font-size": Math.round(window["slider_button1_" + i][0]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"font-size": Math.round(window["slider_button2_" + i][0]) + 'px'}); + $item.find('.qbutton:eq(0)').css({"line-height": Math.round(window["slider_button1_" + i][1]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"line-height": Math.round(window["slider_button2_" + i][1]) + 'px'}); + $item.find('.qbutton:eq(0)').css({"letter-spacing": Math.round(window["slider_button1_" + i][2]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"letter-spacing": Math.round(window["slider_button2_" + i][2]) + 'px'}); + $item.find('.qbutton:eq(0)').css({"height": Math.round(window["slider_button1_" + i][3]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"height": Math.round(window["slider_button2_" + i][3]) + 'px'}); + if(window["slider_button1_" + i][4] != 0) { + $item.find('.qbutton:eq(0)').css({"width": Math.round(window["slider_button1_" + i][4]) + 'px'}); + }else{ + $item.find('.qbutton:eq(0)').css({"width": 'auto'}); + } + if(window["slider_button2_" + i][4] != 0) { + $item.find('.qbutton:eq(1)').css({"width": Math.round(window["slider_button2_" + i][4]) + 'px'}); + }else{ + $item.find('.qbutton:eq(1)').css({"width": 'auto'}); + } + $item.find('.qbutton:eq(0)').css({"padding-left": Math.round(window["slider_button1_" + i][5]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"padding-left": Math.round(window["slider_button2_" + i][5]) + 'px'}); + $item.find('.qbutton:eq(0)').css({"padding-right": Math.round(window["slider_button1_" + i][5]) + 'px'}); + $item.find('.qbutton:eq(1)').css({"padding-right": Math.round(window["slider_button2_" + i][5]) + 'px'}); + + $item.find('.separator').css({"margin-top": Math.round(window["slider_separator_" + i][0]) + 'px'}); + $item.find('.separator').css({"margin-bottom": Math.round(window["slider_separator_" + i][1]) + 'px'}); + + } + + if($this.hasClass('full_screen')){ + $this.css({'height': ($j(window).height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px'}); + $this.find('.qode_slider_preloader').css({'height': ($j(window).height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px'}); + $this.find('.qode_slider_preloader .ajax_loader').css({'display': 'block'}); + $this.find('.item').css({'height': ($j(window).height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px'}); + + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + $j(window).resize(function() { + mobile_header = $j(window).width() < 1000 ? $j('header.page_header').height() : 0; + header_height_add_for_paspartu = $window_width > 1000 && !$j('header.page_header').hasClass('transparent') && $j('body.paspartu_on_top_fixed').length == 0 ? $j('header.page_header').height() : 0; + paspartu_amount_with_top = $j('.paspartu_outer:not(.disable_top_paspartu)').length > 0 ? Math.round($window_width*paspartu_width + header_height_add_for_paspartu) : 0; + paspartu_amount_with_bottom = $j('.paspartu_outer.paspartu_on_bottom_slider').length > 0 ? Math.round($window_width*paspartu_width) : 0; + $this.css({'height': ($j(window).height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px'}); + $this.find('.qode_slider_preloader .ajax_loader').css({'display': 'block'}); + $this.find('.item').css({'height': ($j(window).height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px'}); + + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + if($this.hasClass('advanced_responsiveness')){ + $this.find('.item').each(function(i){ + setSliderElementsSize($j(this),i); + }); + } + }); + }else if($this.hasClass('responsive_height')){ + var $def_height = $this.data('height'); + + $this.find('.qode_slider_preloader').css({'height': ($this.height() - mobile_header - paspartu_amount_with_top - paspartu_amount_with_bottom) + 'px', 'display': 'block'}); + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + setSliderHeight($this, $def_height); + + $j(window).resize(function() { + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + header_height_add_for_paspartu = $window_width > 1000 && !$j('header.page_header').hasClass('transparent') ? $j('header.page_header').height() : 0; + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + setSliderHeight($this, $def_height); + if($this.hasClass('advanced_responsiveness')){ + $this.find('.item').each(function(i){ + setSliderElementsSize($j(this),i); + }); + } + }); + }else { + $this.find('.qode_slider_preloader').css({'height': ($this.height() - mobile_header) + 'px', 'display': 'block'}); + $this.find('.qode_slider_preloader .ajax_loader').css({'display': 'block'}); + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + if($this.hasClass('advanced_responsiveness')){ + $this.find('.item').each(function(i){ + setSliderInitialElementsSize($j(this),i); + setSliderElementsSize($j(this),i); + }); + } + $window_width < 1000 ? setSliderHeight($this, $def_height) : resetSliderHeight($def_height); + + $j(window).resize(function() { + if($j('.paspartu_outer:not(.disable_top_paspartu)').length){ + header_height_add_for_paspartu = $window_width > 1000 && !$j('header.page_header').hasClass('transparent') ? $j('header.page_header').height() : 0; + if(!$j('body').hasClass('paspartu_on_top_fixed')){ + $this.closest('.q_slider').css('padding-top', Math.round(header_height_add_for_paspartu + $window_width * paspartu_width)); + } + } + if($j('.paspartu_outer.paspartu_on_bottom_slider').length){ + $this.closest('.q_slider').css('padding-bottom', Math.round($window_width * paspartu_width)); + } + + if($window_width < 1000){ + setSliderHeight($this, $def_height); + if($this.hasClass('advanced_responsiveness')){ + $this.find('.item').each(function(i){ + setSliderElementsSize($j(this),i); + }); + } + }else{ + resetSliderHeight($def_height); + if($this.hasClass('advanced_responsiveness')){ + $this.find('.item').each(function(i){ + resetSliderElementsSize($j(this),i); + }); + } + } + }); + } + + if($j('body:not(.boxed):not(.vertical_menu_transparency):not(.vertical_menu_hidden):not(.page-template-landing_page-php)').hasClass('vertical_menu_enabled') && $j(window).width() > 1000){ + var paspartu_add = $j('body').hasClass('paspartu_enabled') ? 2*Math.round($window_width*paspartu_width) : 0; //2 times paspartu (left and right side) + $this.find('.carousel-inner').width($window_width - 260 - paspartu_add); + $j(window).resize(function() { + if($j(window).width() > 1000){ + paspartu_add = $j('body').hasClass('paspartu_enabled') ? 2*Math.round($window_width*paspartu_width) : 0; //2 times paspartu (left and right side) + $this.find('.carousel-inner').width($window_width - 260 - paspartu_add); + } else { + $this.find('.carousel-inner').css('width','100%'); + } + }); + } + + if($j('body:not(.boxed):not(.vertical_menu_transparency):not(.page-template-landing_page-php)').hasClass('vertical_menu_hidden') && $window_width > 1000){ + var paspartu_add = $j('body').hasClass('paspartu_enabled') ? 2*Math.round($window_width*paspartu_width) : 0; //2 times paspartu (left and right side) + $this.find('.carousel-inner').width($window_width - 40 - paspartu_add); + $j(window).resize(function() { + if($j(window).width() > 1000){ + paspartu_add = $j('body').hasClass('paspartu_enabled') ? 2*Math.round($window_width*paspartu_width) : 0; //2 times paspartu (left and right side) + $this.find('.carousel-inner').width($window_width - 40 - paspartu_add); + } else { + $this.find('.carousel-inner').css('width','100%'); + } + }); + } + + $j(window).scroll(function() { + if($scroll > ($this.height()+$j('header.page_header').height()) && $j(window).width() > 1000){ + $this.find('.carousel-inner, .carousel-indicators, button').hide(); + }else{ + $this.find('.carousel-inner, .carousel-indicators, button').show(); + } + }); + + var $slide_animation = $this.data('slide_animation'); + if($slide_animation === ""){ + $slide_animation = 6000; + } + + // function for setting prev/next numbers on arrows + var all_items_count = $j('div.item').length; + function setPrevNextNumbers(curr_item, all_items_count){ + if(curr_item == 1){ + $this.find('.left.carousel-control .prev').html(all_items_count); + $this.find('.right.carousel-control .next').html(curr_item + 1); + }else if(curr_item == all_items_count){ + $this.find('.left.carousel-control .prev').html(curr_item - 1); + $this.find('.right.carousel-control .next').html(1); + }else{ + $this.find('.left.carousel-control .prev').html(curr_item - 1); + $this.find('.right.carousel-control .next').html(curr_item + 1); + } + } + + function initSlider(){ + //set active class on first item + $this.find('.carousel-inner .item:first-child').addClass('active'); + checkSliderForHeaderStyle($j('.carousel .active'), $this.hasClass('header_effect')); + + if($this.hasClass('slider_thumbs')){ + // initial state of prev/next numbers + setPrevNextNumbers(1, all_items_count); + + //set prev and next thumb on load + if($this.find('.active').next('div').find('.image').length){ + src = image_regex.exec($this.find('.active').next('div').find('.image').attr('style')); + next_image = new Image(); + next_image.src = src[1]; + }else{ + next_image = $this.find('.active').next('div').find('> .video').clone(); + next_image.find('.video-overlay').remove(); + next_image.find('.video-wrap').width(170).height(95); + next_image.find('.mejs-container').width(170).height(95); + next_image.find('video').width(170).height(95); + } + $this.find('.right.carousel-control .img').html(next_image).find('img, div.video').addClass('old'); + + if($this.find('.carousel-inner .item:last-child .image').length){ + src = image_regex.exec($this.find('.carousel-inner .item:last-child .image').attr('style')); + prev_image = new Image(); + prev_image.src = src[1]; + }else{ + prev_image = $this.find('.carousel-inner .item:last-child > .video').clone(); + prev_image.find('.video-overlay').remove(); + prev_image.find('.video-wrap').width(170).height(95); + prev_image.find('.mejs-container').width(170).height(95); + prev_image.find('video').width(170).height(95); + } + $this.find('.left.carousel-control .img').html(prev_image).find('img, div.video').addClass('old'); + } + + if($this.hasClass('q_auto_start')){ + $this.carousel({ + interval: $slide_animation, + pause: false + }); + } else { + $this.carousel({ + interval: 0, + pause: false + }); + } + if($this.find('.item video').length){ + initVideoBackgroundSize(); + } + + if($this.hasClass('advanced_responsiveness') && ($this.hasClass('responsive_height') || $this.hasClass('full_screen'))){ + $this.find('.item').each(function (i) { + setSliderInitialElementsSize($j(this), i); + setSliderElementsSize($j(this), i); + }); + } + + //initiate image animation + if($j('.carousel-inner .item:first-child').hasClass('animate_image') && $window_width > 1000){ + $this.find('.carousel-inner .item.animate_image:first-child .image').transformAnimate({ + transform: "matrix("+matrixArray[$j('.carousel-inner .item:first-child').data('animate_image')]+")", + duration: 30000 + }); + } + } + + if($j('html').hasClass('touch')){ + if($this.find('.item:first-child .mobile-video-image').length > 0){ + src = image_regex.exec($this.find('.item:first-child .mobile-video-image').attr('style')); + if (src) { + var backImg = new Image(); + backImg.src = src[1]; + $j(backImg).load(function(){ + $j('.qode_slider_preloader').fadeOut(500); + initSlider(); + checkSVG($this); + }); + } + } + else{ + src = image_regex.exec($this.find('.item:first-child .image').attr('style')); + if (src) { + var backImg = new Image(); + backImg.src = src[1]; + $j(backImg).load(function(){ + $j('.qode_slider_preloader').fadeOut(500); + initSlider(); + checkSVG($this); + }); + } + } + } else { + if($this.find('.item:first-child video').length > 0){ + $this.find('.item:first-child video').get(0).addEventListener('loadeddata',function(){ + $j('.qode_slider_preloader').fadeOut(500); + initSlider(); + checkSVG($this); + }); + }else{ + src = image_regex.exec($this.find('.item:first-child .image').attr('style')); + if (src) { + var backImg = new Image(); + backImg.src = src[1]; + $j(backImg).load(function(){ + $j('.qode_slider_preloader').fadeOut(500); + initSlider(); + checkSVG($this); + }); + } + } + } + + $this.on('slide.bs.carousel', function () { + $this.addClass('in_progress'); + $this.find('.active .slider_content_outer').fadeTo(800,0); + }); + $this.on('slid.bs.carousel', function () { + $this.removeClass('in_progress'); + $this.find('.active .slider_content_outer').fadeTo(0,1); + checkSVG($this); + + // initiate image animation on active slide and reset all others + $j('div.item.animate_image .image').stop().css({'transform':'', '-webkit-transform':''}); + if($j('div.item.active').hasClass('animate_image') && $window_width > 1000){ + $j('div.item.animate_image.active .image').transformAnimate({ + transform: "matrix("+matrixArray[$j('div.item.animate_image.active').data('animate_image')]+")", + duration: 30000 + }); + } + + if($this.hasClass('slider_thumbs')){ + var curr_item = $j('div.item').index($j('div.item.active')[0]) + 1; + setPrevNextNumbers(curr_item, all_items_count); + + // prev thumb + if($this.find('.active').prev('div.item').length){ + if($this.find('.active').prev('div').find('.image').length){ + src = image_regex.exec($this.find('.active').prev('div').find('.image').attr('style')); + prev_image = new Image(); + prev_image.src = src[1]; + }else{ + prev_image = $this.find('.active').prev('div').find('> .video').clone(); + prev_image.find('.video-overlay').remove(); + prev_image.find('.video-wrap').width(170).height(95); + prev_image.find('.mejs-container').width(170).height(95); + prev_image.find('video').width(170).height(95); + } + $this.find('.left.carousel-control .img .old').fadeOut(300,function(){ + $j(this).remove(); + }); + $this.find('.left.carousel-control .img').append(prev_image).find('img, div.video').fadeIn(300).addClass('old'); + + }else{ + if($this.find('.carousel-inner .item:last-child .image').length){ + src = image_regex.exec($this.find('.carousel-inner .item:last-child .image').attr('style')); + prev_image = new Image(); + prev_image.src = src[1]; + }else{ + prev_image = $this.find('.carousel-inner .item:last-child > .video').clone(); + prev_image.find('.video-overlay').remove(); + prev_image.find('.video-wrap').width(170).height(95); + prev_image.find('.mejs-container').width(170).height(95); + prev_image.find('video').width(170).height(95); + } + $this.find('.left.carousel-control .img .old').fadeOut(300,function(){ + $j(this).remove(); + }); + $this.find('.left.carousel-control .img').append(prev_image).find('img, div.video').fadeIn(300).addClass('old'); + } + + // next thumb + if($this.find('.active').next('div.item').length){ + if($this.find('.active').next('div').find('.image').length){ + src = image_regex.exec($this.find('.active').next('div').find('.image').attr('style')); + next_image = new Image(); + next_image.src = src[1]; + }else{ + next_image = $this.find('.active').next('div').find('> .video').clone(); + next_image.find('.video-overlay').remove(); + next_image.find('.video-wrap').width(170).height(95); + next_image.find('.mejs-container').width(170).height(95); + next_image.find('video').width(170).height(95); + } + + $this.find('.right.carousel-control .img .old').fadeOut(300,function(){ + $j(this).remove(); + }); + $this.find('.right.carousel-control .img').append(next_image).find('img, div.video').fadeIn(300).addClass('old'); + + }else{ + if($this.find('.carousel-inner .item:first-child .image').length){ + src = image_regex.exec($this.find('.carousel-inner .item:first-child .image').attr('style')); + next_image = new Image(); + next_image.src = src[1]; + }else{ + next_image = $this.find('.carousel-inner .item:first-child > .video').clone(); + next_image.find('.video-overlay').remove(); + next_image.find('.video-wrap').width(170).height(95); + next_image.find('.mejs-container').width(170).height(95); + next_image.find('video').width(170).height(95); + } + $this.find('.right.carousel-control .img .old').fadeOut(300,function(){ + $j(this).remove(); + }); + $this.find('.right.carousel-control .img').append(next_image).find('img, div.video').fadeIn(300).addClass('old'); + } + } + }); + + $this.swipe( { + swipeLeft: function(event, direction, distance, duration, fingerCount){ $this.carousel('next'); }, + swipeRight: function(event, direction, distance, duration, fingerCount){ $this.carousel('prev'); }, + threshold:20 + }); + + }); + + if ($j('.no-touch .carousel').length) { + skrollr_slider = skrollr.init({ + edgeStrategy: 'set', + smoothScrolling: true, + forceHeight: false + }); + skrollr_slider.refresh(); + } + } +} + +function checkSliderForHeaderStyle($this, header_effect){ + "use strict"; + + var slide_header_style = ""; + var navigation_color = $this.data('navigation-color'); + if($this.hasClass('light')){ slide_header_style = 'light';} + if($this.hasClass('dark')){ slide_header_style = 'dark';} + + if( slide_header_style !== ""){ + if(header_effect){ + $j('header.page_header').removeClass('dark light').addClass(slide_header_style); + $j('aside.vertical_menu_area').removeClass('dark light').addClass(slide_header_style); + } + $j('.carousel .carousel-control, .carousel .carousel-indicators').removeClass('dark light').addClass(slide_header_style); + }else{ + if(header_effect){ + $j('header.page_header').removeClass('dark light').addClass(default_header_style); + $j('aside.vertical_menu_area').removeClass('dark light').addClass(default_header_style); + } + $j('.carousel .carousel-control, .carousel .carousel-indicators').removeClass('dark light').addClass(default_header_style); + } + + if(navigation_color !== undefined){ + $j('.carousel-control .thumb_holder .thumb_top, .carousel-indicators li').css('background-color',navigation_color); + $j('.carousel-control .prev_nav, .carousel-control .next_nav').css('border-color',navigation_color); + $j('.carousel-control .prev_nav i, .carousel-control .next_nav i').css('color',navigation_color); + }else{ + $j('.carousel-control .thumb_holder .thumb_top, .carousel-indicators li').css('background-color',''); + $j('.carousel-control .prev_nav, .carousel-control .next_nav').css('border-color',''); + $j('.carousel-control .prev_nav i, .carousel-control .next_nav i').css('color',''); + } +} + +/* + ** Set heights for qode carousel, portfolio slider and blog slider + */ +function calculateHeights(){ + if($j('.portfolio_slides').length){ + $j('.portfolio_slides').each(function(){ + $j(this).parents('.caroufredsel_wrapper').css({'height' : ($j(this).find('li.item').outerHeight()-3) + 'px'}); //3 is because of the white line bellow the slider + }); + } + + if($j('.qode_carousels .slides').length){ + $j('.qode_carousels .slides').each(function(){ + $j(this).parents('.caroufredsel_wrapper').css({'height' : ($j(this).find('li.item').outerHeight()) + 'px'}); + }); + } + + if($j('.blog_slides').length){ + $j('.blog_slides').each(function(){ + $j(this).parents('.caroufredsel_wrapper').css({'height' : ($j(this).find('li.item').outerHeight()-3) + 'px'}); + }); + } +} + +/* + ** Init Qode Carousel + */ +function initQodeCarousel(){ + "use strict"; + + if($j('.qode_carousels').length){ + $j('.qode_carousels').each(function(){ + var itemWidth = ($j(this).parents('.grid_section').length == 1) ? 170 : 315; + $j(this).find('.slides').carouFredSel({ + circular: true, + responsive: true, + scroll : { + items : 1, + duration : 1000, + pauseOnHover : false + }, + items: { + width: itemWidth, + visible: { + min: 1, + max: 6 + } + }, + auto: true, + mousewheel: false, + swipe: { + onMouse: true, + onTouch: true + } + + }).animate({'opacity': 1},1000); + }); + calculateHeights(); + } +} + +/* +** Init Portfolio Slider +*/ +function initPortfolioSlider(){ + "use strict"; + + if($j('.portfolio_slider').length){ + + $j('.portfolio_slider').each(function(){ + + var number_of_items; + var item_width_fw; + if(typeof $j(this).data('number_of_items') !== 'undefined') { + number_of_items = $j(this).data('number_of_items'); + } + else { + number_of_items = 'auto'; + } + + switch(number_of_items){ + case 4: + item_width_fw = 500; + break; + case 5: + item_width_fw = 350; + break; + default: + item_width_fw = 500; + break; + } + + var maxItems = ($j(this).parents('.grid_section').length == 1) ? 3 : number_of_items; + var itemWidth = ($j(this).parents('.grid_section').length == 1) ? 353 : item_width_fw; + + $j(this).find('.portfolio_slides').carouFredSel({ + circular: true, + responsive: true, + scroll: 1, + prev : { + button : function() { + return $j(this).parent().siblings('.caroufredsel-direction-nav').find('#caroufredsel-prev'); + } + }, + next : { + button : function() { + return $j(this).parent().siblings('.caroufredsel-direction-nav').find('#caroufredsel-next'); + } + }, + items: { + width: itemWidth, + visible: { + min: 1, + max: maxItems + } + }, + auto: false, + mousewheel: false, + swipe: { + onMouse: true, + onTouch: true + } + }).animate({'opacity': 1},1000); + }); + + calculateHeights(); + + $j('.portfolio_slider .flex-direction-nav a').click(function(e){ + e.preventDefault(); + e.stopImmediatePropagation(); + e.stopPropagation(); + }); + } +} + +/* + ** Init Blog Slider + */ +function initBlogSlider(){ + "use strict"; + + if($j('.blog_slider').length){ + + $j('.blog_slider').each(function(){ + + var blogs_shown; + var maxItems; + var itemWidth; + var autoPlay = false; + if(typeof $j(this).data('blogs_shown') !== 'undefined') { + blogs_shown = $j(this).data('blogs_shown'); + } + else if($j(this).hasClass('simple_slider')){ + blogs_shown = 1; + } + else{ + blogs_shown = 'auto'; + } + + if ($j(this).hasClass('simple_slider')) { + maxItems = 1; + itemWidth = 300; + autoPlay = false; + } + else { + maxItems = ($j(this).parents('.grid_section').length == 1) ? 3 : blogs_shown; + var itemWidthTemp; + + switch (blogs_shown) { + case 3: + itemWidthTemp = 667; + break; + case 4: + itemWidthTemp = 500; + break; + case 5: + itemWidthTemp = 400; + break; + case 6: + itemWidthTemp = 334; + break; + default: + itemWidthTemp = 500; + + break; + } + + itemWidth = ($j(this).parents('.grid_section').length == 1) ? 353 : itemWidthTemp; + } + + $j(this).find('.blog_slides').carouFredSel({ + circular: true, + responsive: true, + scroll: 1, + prev : { + button : function() { + return $j(this).parent().siblings('.caroufredsel-direction-nav').find('#caroufredsel-prev'); + } + }, + next : { + button : function() { + return $j(this).parent().siblings('.caroufredsel-direction-nav').find('#caroufredsel-next'); + } + }, + items: { + width: itemWidth, + visible: { + min: 1, + max: maxItems + } + }, + auto: autoPlay, + mousewheel: false, + swipe: { + onMouse: true, + onTouch: true + } + }).animate({'opacity': 1},1000); + }); + + calculateHeights(); + + $j('.blog_slider .flex-direction-nav a').click(function(e){ + e.preventDefault(); + e.stopImmediatePropagation(); + e.stopPropagation(); + }); + } +} + +/* +** Opening side menu on "menu button" click +*/ +var current_scroll; +function initSideMenu(){ + "use strict"; + + if ($j('body').hasClass('side_area_uncovered_from_content')) { + $j('.side_menu_button_wrapper a.side_menu_button_link, a.close_side_menu').click(function(e){ + e.preventDefault(); + $j('.side_menu').css({'right':'0'}); + if(!$j('.side_menu_button_wrapper a.side_menu_button_link').hasClass('opened')){ + $j('.side_menu').css({'visibility':'visible'}); + $j(this).addClass('opened'); + $j('body').addClass('right_side_menu_opened'); + current_scroll = $j(window).scrollTop(); + + $j(window).scroll(function() { + if(Math.abs($scroll - current_scroll) > 400){ + $j('body').removeClass('right_side_menu_opened'); + $j('.side_menu_button_wrapper a').removeClass('opened'); + var hide_side_menu = setTimeout(function(){ + $j('.side_menu').css({'visibility':'hidden'}); + clearTimeout(hide_side_menu); + },400); + } + }); + }else{ + $j('.side_menu_button_wrapper a.side_menu_button_link').removeClass('opened'); + $j('body').removeClass('right_side_menu_opened'); + var hide_side_menu = setTimeout(function(){ + $j('.side_menu').css({'visibility':'hidden'}); + clearTimeout(hide_side_menu); + },400); + } + }); + } + + if ($j('body').hasClass('side_menu_slide_with_content')) { + $j('.side_menu_button_wrapper a.side_menu_button_link, a.close_side_menu').click(function(e){ + e.preventDefault(); + + if(!$j('.side_menu_button_wrapper a.side_menu_button_link').hasClass('opened')){ + $j(this).addClass('opened'); + $j('body').addClass('side_menu_open'); + current_scroll = $j(window).scrollTop(); + $j(window).scroll(function() { + + if(Math.abs($scroll - current_scroll) > 400){ + $j('body').removeClass('side_menu_open'); + $j('.side_menu_button_wrapper a').removeClass('opened'); + } + }); + }else{//hamburger icon has class open on its click + $j('body').removeClass('side_menu_open'); + + + $j('.side_menu_button_wrapper a.side_menu_button_link').removeClass('opened'); + $j('body').removeClass('side_menu_open'); + + } + + e.stopPropagation(); + $j('.wrapper').click(function() { + e.preventDefault(); + $j('body').removeClass('side_menu_open'); + $j('.side_menu_button_wrapper a.side_menu_button_link').removeClass('opened'); + $j('body').removeClass('side_menu_open'); + }); + }); + } + + + if ($j('body').hasClass('side_menu_slide_from_right')) { + $j('.wrapper').prepend('
'); + $j('.side_menu_button_wrapper a.side_menu_button_link, a.close_side_menu').click(function(e){ + e.preventDefault(); + + if(!$j('.side_menu_button_wrapper a.side_menu_button_link').hasClass('opened')){ + $j(this).addClass('opened'); + $j('body').addClass('right_side_menu_opened'); + + $j(' .wrapper .cover').click(function() { + $j('.side_menu_button_wrapper a.side_menu_button_link').removeClass('opened'); + $j('body').removeClass('right_side_menu_opened'); + $j('.side_menu_button_wrapper a').removeClass('opened'); + }); + current_scroll = $j(window).scrollTop(); + $j(window).scroll(function() { + if(Math.abs($scroll - current_scroll) > 400){ + $j('body').removeClass('right_side_menu_opened'); + $j('.side_menu_button_wrapper a').removeClass('opened'); + } + }); + }else{ + $j('.side_menu_button_wrapper a.side_menu_button_link').removeClass('opened'); + $j('body').removeClass('right_side_menu_opened'); + } + }); + } +} + +function setDropDownMenuPosition(){ + "use strict"; + + var menu_items = $j(".drop_down > ul > li.narrow"); + menu_items.each( function(i) { + + var browser_width = $j(window).width()-16; // 16 is width of scroll bar + var boxed_layout = 1150; // boxed layout width + var menu_item_position = $j(menu_items[i]).offset().left; + var sub_menu_width = $j(menu_items[i]).find('.second .inner ul').width(); + var menu_item_from_left = 0; + if($j('body').hasClass('boxed')){ + menu_item_from_left = boxed_layout - (menu_item_position - (browser_width - boxed_layout)/2) + 17; // 17 is right padding between menu elements + } else { + menu_item_from_left = browser_width - menu_item_position + 17; // 17 is right padding between menu elements + } + var sub_menu_from_left; + + if($j(menu_items[i]).find('li.sub').length > 0){ + sub_menu_from_left = menu_item_from_left - sub_menu_width; + } + + if(menu_item_from_left < sub_menu_width || sub_menu_from_left < sub_menu_width){ + $j(menu_items[i]).find('.second').addClass('right'); + $j(menu_items[i]).find('.second .inner ul').addClass('right'); + } + }); +} + +function initDropDownMenu(){ + "use strict"; + + var menu_items = $j('.drop_down > ul > li'); + + menu_items.each( function(i) { + if ($j(menu_items[i]).find('.second').length > 0) { + if($j(menu_items[i]).hasClass('wide')){ + var dropdown = $j(this).find('.inner > ul'); + var dropdownPadding = parseInt(dropdown.css('padding-left').slice(0, -2)) + parseInt(dropdown.css('padding-right').slice(0, -2)); + + if(!$j(this).hasClass('left_position') && !$j(this).hasClass('right_position')){ + $j(this).find('.second').css('left',0); + } + + var tallest = 0; + $j(this).find('.second > .inner > ul > li').each(function() { + var thisHeight = $j(this).height(); + if(thisHeight > tallest) { + tallest = thisHeight; + } + }); + + $j(this).find('.second > .inner > ul > li').height(tallest); + + var row_number; + if($j(this).find('.second > .inner > ul > li').length > 4){ + row_number = 4; + }else{ + row_number = $j(this).find('.second > .inner > ul > li').length; + } + + var width = row_number*($j(this).find('.second > .inner > ul > li').outerWidth()); + $j(this).find('.second > .inner > ul').width(width); + + if(!$j(this).hasClass('wide_background')){ + if(!$j(this).hasClass('left_position') && !$j(this).hasClass('right_position')){ + var left_position = ($j(window).width() - 2 * ($j(window).width()-$j(this).find('.second').offset().left))/2 + (width+dropdownPadding)/2; + $j(this).find('.second').css('left',-left_position); + } + } else{ + if(!$j(this).hasClass('left_position') && !$j(this).hasClass('right_position')){ + var left_position = $j(this).find('.second').offset().left; + $j(this).find('.second').css('left',-left_position); + $j(this).find('.second').css('width',$j(window).width()); + } + } + } + + if(!menu_dropdown_height_set){ + $j(menu_items[i]).data('original_height', $j(menu_items[i]).find('.second').height() + 'px'); + $j(menu_items[i]).find('.second').height(0); + } + + if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) { + $j(menu_items[i]).on("touchstart mouseenter",function(){ + $j(menu_items[i]).find('.second').css({'height': $j(menu_items[i]).data('original_height'), 'overflow': 'visible', 'visibility': 'visible', 'opacity': '1'}); + }).on("mouseleave", function(){ + $j(menu_items[i]).find('.second').css({'height': '0px','overflow': 'hidden', 'visivility': 'hidden', 'opacity': '0'}); + }); + + }else{ + var config = { + interval: 0, + over: function(){ + setTimeout(function() { + $j(menu_items[i]).find('.second').addClass('drop_down_start'); + $j(menu_items[i]).find('.second').stop().css({'height': $j(menu_items[i]).data('original_height')}); + }, 150); + }, + timeout: 150, + out: function(){ + $j(menu_items[i]).find('.second').stop().css({'height': '0px'}); + $j(menu_items[i]).find('.second').removeClass('drop_down_start'); + } + }; + $j(menu_items[i]).hoverIntent(config); + } + } + }); + $j('.drop_down ul li.wide ul li a, .drop_down ul li.narrow ul li a').on('click',function(){ + var $this = $j(this); + + if(!$this.next('ul').length && ($this.attr('href') !== "http://#") && ($this.attr('href') !== "#") && !$this.hasClass('no_link')) { + setTimeout(function() { + $this.mouseleave(); + }, 500); + } + }); + + menu_dropdown_height_set = true; +} + + +/* + ** Vertical menu toggle dropdown + */ + +function initVerticalMenu(){ + "use strict"; + + if ($j('.no-touch .vertical_menu_toggle').length) { + var menu_items = $j('.no-touch .vertical_menu_toggle > ul > li'); + var menu_items_2 = $j('.no-touch .vertical_menu_toggle ul li ul li'); + + menu_items.each( function(i) { + if($j(menu_items[i]).hasClass('has_sub')){ + var subitems_number = $j(menu_items[i]).find('.inner > ul > li').length; + $j(menu_items[i]).hoverIntent({ + over: function() { + $j(menu_items[i]).addClass('open'); + $j(menu_items[i]).find('.second').slideDown(subitems_number*40, 'easeInOutSine', function(){ + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + + }, + out: function() { + //if(!$j(menu_items[i]).hasClass('active')){ + $j(menu_items[i]).removeClass('open'); + $j(menu_items[i]).find('.second').slideUp(subitems_number*40, 'easeInOutSine'); + //} + }, + timeout: 1000 + }); + } + }); + + menu_items_2.each( function(i) { + if($j(menu_items_2[i]).hasClass('menu-item-has-children')){ + var subitems_number = $j(menu_items_2[i]).find('ul > li').length; + $j(menu_items_2[i]).hoverIntent({ + over: function() { + $j(menu_items_2[i]).addClass('open'); + $j(menu_items_2[i]).find('ul').slideDown(subitems_number*40, 'easeInOutSine', function(){ + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + }, + out: function() { + $j(menu_items_2[i]).removeClass('open'); + $j(menu_items_2[i]).find('ul').slideUp(subitems_number*40, 'easeInOutSine'); + }, + timeout: 1000 + }); + } + }); + } + else if ($j('.vertical_menu_on_click').length) { + var menu_items = $j('.vertical_menu_on_click > ul > li > a'); + var menu_items_2 = $j('.vertical_menu_on_click ul li ul li a'); + + menu_items.each( function(i) { + if($j(menu_items[i]).parent().hasClass('has_sub')){ + $j(menu_items[i]).on('tap click',function(e) { + e.preventDefault(); + if(!$j(this).parent().hasClass('open')) { + $j('.vertical_menu_on_click > ul > li').removeClass('open'); + $j('.vertical_menu_on_click > ul > li').find('.second').slideUp('fast'); + + $j(this).parent().addClass('open'); + $j(this).parent().find('.second').slideDown('slow', function () { + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + }else{ + + $j(this).parent().removeClass('open'); + $j(this).parent().find('.second').slideUp('fast', function () { + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + } + return false; + }); + } + }); + + menu_items_2.each( function(i) { + if($j(menu_items_2[i]).parent().hasClass('menu-item-has-children')){ + $j(menu_items_2[i]).on('tap click',function(e) { + e.preventDefault(); + if(!$j(this).parent().hasClass('open')) { + $j('.vertical_menu_on_click ul li ul li').removeClass('open'); + $j('.vertical_menu_on_click ul li ul li').find('ul').slideUp('fast'); + + $j(this).parent().addClass('open'); + $j(this).parent().find('ul').slideDown('slow', function () { + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + }else{ + $j(this).parent().removeClass('open'); + $j(this).parent().find('ul').slideUp('fast', function () { + $j('.vertical_menu_area.with_scroll').getNiceScroll().resize(); + }); + } + return false; + }); + } + }); + } + else if ($j('.no-touch .vertical_menu_float').length){ + //show dropdown to content on menu item hover, link is available on menu item click + var menu_items = $j('.no-touch .vertical_menu_float > ul > li'); + var menu_items_2 = $j('.no-touch .vertical_menu_float ul li ul li'); + menu_items.each( function(i) { + if($j(menu_items[i]).hasClass('has_sub')){ + $j(menu_items[i]).hoverIntent({ + over: function() { + $j(menu_items[i]).addClass('open'); + $j(menu_items[i]).find('.second').addClass('vertical_menu_start'); + }, + out: function() { + //if(!$j(menu_items[i]).hasClass('active')){ + $j(menu_items[i]).removeClass('open'); + $j(menu_items[i]).find('.second').removeClass('vertical_menu_start'); + }, + timeout: 300 + }); + } + }); + + menu_items_2.each( function(i) { + if($j(menu_items_2[i]).hasClass('menu-item-has-children')){ + var subitems_number = $j(menu_items_2[i]).find('ul > li').length; + $j(menu_items_2[i]).hoverIntent({ + over: function() { + $j(menu_items_2[i]).addClass('open'); + $j(menu_items_2[i]).find('ul').addClass('vertical_submenu_start'); + }, + out: function() { + $j(menu_items_2[i]).removeClass('open'); + $j(menu_items_2[i]).find('ul').removeClass('vertical_submenu_start'); + }, + timeout: 300 + }); + } + }); + } + +} + +/* + ** Show/Hide Vertical menu for mobile + */ +function initVerticalMobileMenu(){ + "use strict"; + + if ($j('.vertical_menu_toggle').length) { + //register tap / click event for main menu item plus icon + $j('.touch .vertical_menu_toggle > ul > li.has_sub > a .plus').on('tap click', function(e){ + //first prevent event propagation and it's default behavior + e.stopPropagation(); + e.preventDefault(); + + //is dropdown for clicked item visible? + if($j(this).parent().next('div.second').is(":visible")){ + //if it is remove 'open' class and slide it up + $j(this).parents('.touch .vertical_menu_toggle > ul > li.has_sub').removeClass('open'); + $j(this).parent().next('div.second').slideUp(200); + } else { + //if it's not visible add 'open' class and slide it down + $j(this).parents('.touch .vertical_menu_toggle > ul > li.has_sub').addClass('open'); + $j(this).parent().next('div.second').slideDown(200); + } + }); + + //register tap / click event for second level main menu item plus icon + $j('.touch .vertical_menu_toggle ul li ul li > a .plus').on('tap click', function(e){ + //first prevent event propagation and it's default behavior + e.stopPropagation(); + e.preventDefault(); + + //is dropdown for clicked item visible? + if($j(this).parent().next('ul').is(":visible")){ + //if it is remove 'open' class and slide it up + $j(this).parents('.touch .vertical_menu_toggle ul li ul li').removeClass('open'); + $j(this).parent().next('ul').slideUp(200); + } else { + //if it's not visible add 'open' class and slide it down + $j(this).parents('.touch .vertical_menu_toggle ul li ul li').addClass('open'); + $j(this).parent().next('ul').slideDown(200); + } + }); + } + else if ($j('.vertical_menu_float').length){ + $j('.touch .vertical_menu_float > ul > li.has_sub > a .plus').on('tap click', function(e){ + //first prevent event propagation and it's default behavior + e.stopPropagation(); + e.preventDefault(); + + //is dropdown for clicked item visible? + if($j(this).parent().next('div.second').hasClass('vertical_menu_start')){ + //if it is remove 'open' class and 'vertical_menu_start' + $j(this).parents('.touch .vertical_menu_float > ul > li.has_sub').removeClass('open'); + $j(this).parents('.touch .vertical_menu_float > ul > li.has_sub').find('.second').removeClass('vertical_menu_start'); + } else { //if it's not visible add 'open' class and 'vertical_menu_start' + $j(this).parents('.touch .vertical_menu_float > ul > li.has_sub').addClass('open'); + $j(this).parents('.touch .vertical_menu_float > ul > li.has_sub').find('.second').addClass('vertical_menu_start'); + } + }); + //register tap / click event for second level main menu item plus icon + $j('.touch .vertical_menu_float ul li ul li > a .plus').on('tap click', function(e){ + //first prevent event propagation and it's default behavior + e.stopPropagation(); + e.preventDefault(); + + //is dropdown for clicked item visible? + if($j(this).parent().next('ul').hasClass('vertical_submenu_start')){ + //if it is remove 'open' class and slide it up + $j(this).parents('.touch .vertical_menu_float ul li ul li').removeClass('open'); + $j(this).parents('.touch .vertical_menu_float ul li ul li').find('ul').removeClass('vertical_submenu_start'); + + } else { + //if it's not visible add 'open' class and slide it down + $j(this).parents('.touch .vertical_menu_float ul li ul li').addClass('open'); + $j(this).parents('.touch .vertical_menu_float ul li ul li').find('ul').addClass('vertical_submenu_start'); + } + }); + } +} + +/* + ** Set transparency for left menu area + */ +function checkVerticalMenuTransparency(){ + if($scroll !== 0){ + $j('body.vertical_menu_transparency').removeClass('vertical_menu_transparency_on'); + }else{ + $j('body.vertical_menu_transparency').addClass('vertical_menu_transparency_on'); + } +} + +/* + ** Show/Hide hidden Vertical menu + */ +function showHideVerticalMenu(){ + + if($j('.vertical_menu_hidden').length) { + var vertical_menu = $j('aside.vertical_menu_area'); + var vertical_menu_bottom_logo = $j('.vertical_menu_area_bottom_logo'); + var hovered_flag = true; + + $j('.vertical_menu_hidden_button').on('click',function (e) { + e.preventDefault(); + if(hovered_flag) { + hovered_flag = false; + current_scroll = $j(window).scrollTop(); //current scroll is defined in front of "initSideMenu" function + vertical_menu.addClass('active'); + vertical_menu_bottom_logo.addClass('active'); + }else{ + hovered_flag = true; + vertical_menu.removeClass('active'); + vertical_menu_bottom_logo.removeClass('active'); + } + }); + + $j(window).scroll(function() { + if(Math.abs($scroll - current_scroll) > 400){ + hovered_flag = true; + vertical_menu.removeClass('active'); + vertical_menu_bottom_logo.removeClass('active'); + } + }); + + //take click outside vertical left/rifgt area and close it + (function() { + var Outclick, outclick, + _this = this; + Outclick = (function() { + Outclick.name = 'Outclick'; + function Outclick() { + this.objects = []; + } + Outclick.prototype.check = function(element, event) { + return !element.is(event.target) && element.has(event.target).length === 0; + }; + Outclick.prototype.trigger = function(e) { + var execute, + _this = this; + execute = false; + return $j.each(this.objects, function(index, el) { + if (_this.check(el.container, e)) { + if (el.related.length < 1) { + execute = true; + } else { + $j.each(el.related, function(index, relation) { + if (_this.check(relation, e)) { + return execute = true; + } else { + execute = false; + return false; + } + }); + } + if (execute) { + return el.callback.call(el.container); + } + } + }); + }; + return Outclick; + })(); + outclick = new Outclick; + $j.fn.outclick = function(options) { + var _this = this; + if (options == null) { + options = {}; + } + options.related || (options.related = []); + options.callback || (options.callback = function() { + return _this.hide(); + }); + return outclick.objects.push({ + container: this, + related: options.related, + callback: options.callback + }); + }; + $j(document).mouseup(function(e) { + return outclick.trigger(e); + }); + }).call(this); + $j(vertical_menu).outclick({ + callback: function() { + hovered_flag = true; + vertical_menu.removeClass('active'); + vertical_menu_bottom_logo.removeClass('active'); + } + }); + } +} + +/* +** Plugin for counter shortcode +*/ +(function($) { + "use strict"; + + $.fn.countTo = function(options) { + // merge the default plugin settings with the custom options + options = $.extend({}, $.fn.countTo.defaults, options || {}); + + // how many times to update the value, and how much to increment the value on each update + var loops = Math.ceil(options.speed / options.refreshInterval), + increment = (options.to - options.from) / loops; + + return $(this).each(function() { + var _this = this, + loopCount = 0, + value = options.from, + interval = setInterval(updateTimer, options.refreshInterval); + + function updateTimer() { + value += increment; + loopCount++; + $(_this).html(value.toFixed(options.decimals)); + + if (typeof(options.onUpdate) === 'function') { + options.onUpdate.call(_this, value); + } + + if (loopCount >= loops) { + clearInterval(interval); + value = options.to; + + if (typeof(options.onComplete) === 'function') { + options.onComplete.call(_this, value); + } + } + } + }); + }; + + $.fn.countTo.defaults = { + from: 0, // the number the element should start at + to: 100, // the number the element should end at + speed: 1000, // how long it should take to count between the target numbers + refreshInterval: 100, // how often the element should be updated + decimals: 0, // the number of decimal places to show + onUpdate: null, // callback method for every time the element is updated, + onComplete: null // callback method for when the element finishes updating + }; +})(jQuery); + +/* +** Counter from zero to defined number +*/ +function initToCounter(){ + "use strict"; + + if($j('.counter.zero').length){ + $j('.counter.zero').each(function() { + if(!$j(this).hasClass('executed')){ + $j(this).addClass('executed'); + if($j(this).parents('.vertical_split_slider').length){ + $j(this).parent().css('opacity', '1'); + var $max = parseFloat($j(this).text()); + $j(this).countTo({ + from: 0, + to: $max, + speed: 1500, + refreshInterval: 100 + }); + } + else{ + $j(this).appear(function() { + $j(this).parent().css('opacity', '1'); + var $max = parseFloat($j(this).text()); + $j(this).countTo({ + from: 0, + to: $max, + speed: 1500, + refreshInterval: 100 + }); + },{accX: 0, accY: -200}); + } + } + }); + } +} + +/* +** Counter with random effect +*/ +function initCounter(){ + "use strict"; + + if($j('.counter.random').length){ + $j('.counter.random').each(function() { + if(!$j(this).hasClass('executed')){ + $j(this).addClass('executed'); + if($j(this).parents('.vertical_split_slider').length){ + $j(this).parent().css('opacity', '1'); + $j(this).absoluteCounter({ + speed: 2000, + fadeInDelay: 1000 + }); + } + else{ + $j(this).appear(function() { + $j(this).parent().css('opacity', '1'); + $j(this).absoluteCounter({ + speed: 2000, + fadeInDelay: 1000 + }); + },{accX: 0, accY: -200}); + } + } + }); + } +} + +/* +** Countdown +*/ + +function initCountdown(){ + "use strict"; + if($j('.countdown').length){ + $j('.countdown').each(function(){ + + var countdownId = $j(this).attr('id'); + var $this = $j('#'+countdownId); + var year = 0; + var month = 0; + var day = 0; + var hour = 0; + var minute = 0; + var monthsLabel; + var monthLabel; + var daysLabel; + var dayLabel; + var hoursLabel; + var hourLabel; + var minutesLabel; + var minuteLabel; + var secondsLabel; + var secondLabel; + var tickf; + var timezone; + var digitfs; + var labelfs; + var color; + + if(typeof $this.data('year') !== 'undefined' && $this.data('year') !== false) { + year = $this.data('year'); + } + if(typeof $this.data('month') !== 'undefined' && $this.data('month') !== false) { + month = $this.data('month'); + } + if(typeof $this.data('day') !== 'undefined' && $this.data('day') !== false) { + day = $this.data('day'); + } + if(typeof $this.data('hour') !== 'undefined' && $this.data('hour') !== false) { + hour = $this.data('hour'); + } + if(typeof $this.data('minute') !== 'undefined' && $this.data('minute') !== false) { + minute = $this.data('minute'); + } + if(typeof $this.data('monthslabel') !== 'undefined' && $this.data('monthslabel') !== false) { + monthsLabel = $this.data('monthslabel'); + } + if(typeof $this.data('monthlabel') !== 'undefined' && $this.data('monthlabel') !== false) { + monthLabel = $this.data('monthlabel'); + } + if(typeof $this.data('dayslabel') !== 'undefined' && $this.data('dayslabel') !== false) { + daysLabel = $this.data('dayslabel'); + } + if(typeof $this.data('daylabel') !== 'undefined' && $this.data('daylabel') !== false) { + dayLabel = $this.data('daylabel'); + } + if(typeof $this.data('hourslabel') !== 'undefined' && $this.data('hourslabel') !== false) { + hoursLabel = $this.data('hourslabel'); + } + if(typeof $this.data('hourlabel') !== 'undefined' && $this.data('hourlabel') !== false) { + hourLabel = $this.data('hourlabel'); + } + if(typeof $this.data('minuteslabel') !== 'undefined' && $this.data('minuteslabel') !== false) { + minutesLabel = $this.data('minuteslabel'); + } + if(typeof $this.data('minutelabel') !== 'undefined' && $this.data('minutelabel') !== false) { + minuteLabel = $this.data('minuteLabel'); + } + if(typeof $this.data('secondslabel') !== 'undefined' && $this.data('secondslabel') !== false) { + secondsLabel = $this.data('secondslabel'); + } + if(typeof $this.data('secondlabel') !== 'undefined' && $this.data('secondlabel') !== false) { + secondLabel = $this.data('secondlabel'); + } + if(typeof $this.data('tickf') !== 'undefined' && $this.data('tickf') !== false) { + tickf = $this.data('tickf'); + } + if(typeof $this.data('timezone') !== 'undefined' && $this.data('timezone') !== false) { + timezone = $this.data('timezone'); + } + if(typeof $this.data('digitfs') !== 'undefined' && $this.data('digitfs') !== false) { + digitfs = $this.data('digitfs'); + } + if(typeof $this.data('labelfs') !== 'undefined' && $this.data('labelfs') !== false) { + labelfs = $this.data('labelfs'); + } + if(typeof $this.data('color') !== 'undefined' && $this.data('color') !== false) { + color = $this.data('color'); + } + + $this.countdown({ + until: new Date( year, month - 1, day, hour, minute, 44), + labels: ['Years', monthsLabel, 'Weeks', daysLabel, hoursLabel, minutesLabel, secondsLabel], + labels1: ['Year', monthLabel, 'Week', dayLabel, hourLabel, minuteLabel, secondLabel], + format: 'ODHMS', + timezone: timezone, + padZeroes: true, + significant: 0, + onTick: function(){ + if (digitfs !== 'undefined' && digitfs !== ''){ + $this.find('.countdown-amount').css('font-size',digitfs + 'px').css('line-height',digitfs + 'px'); + } + if (labelfs !== 'undefined' && labelfs !== ''){ + $this.find('.countdown-period').css('font-size',labelfs + 'px'); + } + if (color !== 'undefined' && color !== ''){ + $this.find('.countdown_separator').css('background-color',color); + } + } + }); + }); + } +} + +/* +** Horizontal progress bars shortcode +*/ +function initProgressBars(){ + "use strict"; + + if($j('.q_progress_bar').length){ + $j('.q_progress_bar').each(function() { + if($j(this).parents('.vertical_split_slider').length){ + initToCounterHorizontalProgressBar($j(this)); + var percentage = $j(this).find('.progress_content').data('percentage'); + $j(this).find('.progress_content').css('width', '0%'); + $j(this).find('.progress_content').animate({'width': percentage+'%'}, 1500); + $j(this).find('.progress_number_wrapper').css('width', '0%'); + $j(this).find('.progress_number_wrapper').animate({'width': percentage+'%'}, 1500); + } + else { + $j(this).appear(function() { + initToCounterHorizontalProgressBar($j(this)); + var percentage = $j(this).find('.progress_content').data('percentage'); + $j(this).find('.progress_content').css('width', '0%'); + $j(this).find('.progress_content').animate({'width': percentage+'%'}, 1500); + $j(this).find('.progress_number_wrapper').css('width', '0%'); + $j(this).find('.progress_number_wrapper').animate({'width': percentage+'%'}, 1500); + + + },{accX: 0, accY: -200}); + } + }); + } +} + +/* +** Counter for horizontal progress bars percent from zero to defined percent +*/ +function initToCounterHorizontalProgressBar($this){ + "use strict"; + + var percentage = parseFloat($this.find('.progress_content').data('percentage')); + if($this.find('.progress_number span').length) { + $this.find('.progress_number span').each(function() { + $j(this).parents('.progress_number_wrapper').css('opacity', '1'); + $j(this).countTo({ + from: 0, + to: percentage, + speed: 1500, + refreshInterval: 50 + }); + }); + } +} + +/* +** Unordered list animation effect +*/ +function initListAnimation(){ + "use strict"; + + if($j('.animate_list').length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.animate_list').each(function(){ + $j(this).appear(function() { + $j(this).find("li").each(function (l) { + var k = $j(this); + setTimeout(function () { + k.animate({ + opacity: 1, + top: 0 + }, 1500); + }, 100*l); + }); + },{accX: 0, accY: -200}); + }); + } +} + +/* +** Pie Chart shortcode +*/ +function initPieChart(){ + "use strict"; + + if($j('.q_percentage').length){ + $j('.q_percentage').each(function() { + + var $barColor = piechartcolor; + + if($j(this).data('active') !== ""){ + $barColor = $j(this).data('active'); + } + + var $trackColor = '#eeeeee'; + + if($j(this).data('noactive') !== ""){ + $trackColor = $j(this).data('noactive'); + } + + var $line_width = 10; + + if($j(this).data('linewidth') !== ""){ + $line_width = $j(this).data('linewidth'); + } + + var $size = 174; + + $j(this).appear(function() { + initToCounterPieChart($j(this)); + $j(this).parent().css('opacity', '1'); + + $j(this).easyPieChart({ + barColor: $barColor, + trackColor: $trackColor, + scaleColor: false, + lineCap: 'butt', + lineWidth: $line_width, + animate: 1500, + size: $size + }); + },{accX: 0, accY: -200}); + }); + } +} + +/* +** Pie Chart shortcode +*/ +function initPieChartWithIcon(){ + "use strict"; + + if($j('.q_percentage_with_icon').length){ + $j('.q_percentage_with_icon').each(function() { + + var $barColor = piechartcolor; + + if($j(this).data('active') !== ""){ + $barColor = $j(this).data('active'); + } + + var $trackColor = '#eeeeee'; + + if($j(this).data('noactive') !== ""){ + $trackColor = $j(this).data('noactive'); + } + + var $line_width = 10; + + if($j(this).data('linewidth') !== ""){ + $line_width = $j(this).data('linewidth'); + } + + var $size = 174; + + $j(this).appear(function() { + $j(this).parent().css('opacity', '1'); + $j(this).css('opacity', '1'); + $j(this).easyPieChart({ + barColor: $barColor, + trackColor: $trackColor, + scaleColor: false, + lineCap: 'butt', + lineWidth: $line_width, + animate: 1500, + size: $size + }); + },{accX: 0, accY: -200}); + }); + } +} + +/* +** Counter for pie chart number from zero to defined number +*/ +function initToCounterPieChart($this){ + "use strict"; + + $j($this).css('opacity', '1'); + var $max = parseFloat($j($this).find('.tocounter').text()); + $j($this).find('.tocounter').countTo({ + from: 0, + to: $max, + speed: 1500, + refreshInterval: 50 + }); +} + +/* +** Init Portfolio list and Portfolio Filter +*/ +function initPortfolio(){ + "use strict"; + + if($j('.projects_holder_outer:not(.masonry_with_space)').length){ + $j('.projects_holder_outer').each(function(){ + + $j('.filter_holder').each(function(){ + var filter_height = 0; + $j(this).find('li.filter').each(function(){ + filter_height += $j(this).height(); + }); + + $j(this).on('click',function(data){ + var $drop = $j(this), + $bro = $drop.siblings('.hidden'); + + if(!$drop.hasClass('expanded')){ + $drop.find('ul').css('z-index','1000'); + $drop.find('ul').height(filter_height+39); //36 is height of first default item + 1 border * 2 + 1 border on li + $drop.addClass('expanded'); + var label = $drop.find('.label span'); + label.text(label.attr('data-label')); + } else { + $drop.find('ul').height(36); + $drop.removeClass('expanded'); + + var $selected = $j(data.target), + ndx = $selected.index(); + + if($bro.length){ + $bro.find('option').removeAttr('selected').eq(ndx).attr('selected','selected').change(); + } + } + }); + }); + + $j('.filter_holder .filter').on('click',function(){ + var $this = $j(this).text(); + var dropLabels = $j('.filter_holder').find('.label span'); + dropLabels.each(function(){ + $j(this).text($this); + }); + }); + + var currentPortfolio = $j(this).find('.projects_holder'); + + if(currentPortfolio.hasClass('v1')){ + var timeArray= new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25); + }else if(currentPortfolio.hasClass('v2')){ + var timeArray= new Array(1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20); + }else if(currentPortfolio.hasClass('v3')){ + var timeArray= new Array(1,2,3,2,3,4,3,4,5,4,5,6,5,6,7,6,7,8,7,8,9,8,9,10,9,10,11,10,11,12,11,12,13,12,13,14,13,14,15,14,15,16,15,16,17,16,17,18,17,18,19,18,19,20,19,20,21,20,21,22); + }else if(currentPortfolio.hasClass('v4')){ + var timeArray= new Array(1,2,3,4,2,3,4,5,3,4,5,6,4,5,6,7,5,6,7,8,6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12,10,11,12,13,11,12,13,14,12,13,14,15,13,14,15,16,14,15,16,17,15,16,17,18,16,17,18,19,17,18,19,20,18,19,20,21); + }else if(currentPortfolio.hasClass('v5')){ + var timeArray= new Array(1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,4,5,6,7,8,5,6,7,8,9,6,7,8,9,10,7,8,9,10,11,8,9,10,11,12,9,10,11,12,13,10,11,12,13,14,11,12,13,14,15,12,13,14,15,16,13,14,15,16,17,14,15,16,17,18,15,16,17,18,19,20,16,17,18,19,20,17,18,19,20,21,18,19,20,21,22,19,20,21,22,23); + }else if(currentPortfolio.hasClass('v6')){ + var timeArray= new Array(1,2,3,4,5,6,2,3,4,5,6,7,3,4,5,6,7,8,4,5,6,7,8,9,5,6,7,8,9,10,6,7,8,9,10,11,7,8,9,10,11,12,8,9,10,11,12,13,9,10,11,12,13,14,10,11,12,13,14,15,11,12,13,14,15,16,12,13,14,15,16,17,13,14,15,16,17,18,14,15,16,17,18,19,15,16,17,18,19,20,16,17,18,19,20,21,17,18,19,20,21,22); + } + + currentPortfolio.mixitup({ + showOnLoad: 'all', + transitionSpeed: 600, + minHeight: 150, + onMixLoad: function(){ + $j('.projects_holder').addClass('hideItems'); + $j('.projects_holder article').css('visibility','visible'); + + if(currentPortfolio.hasClass('portfolio_one_by_one')) { + currentPortfolio.find('article').each(function(l) { + var currentPortfolioItem = $j(this); + if($j('.vertical_split_slider').length){ + var acc = 0; + }else{ + var acc = -150; + } + + setTimeout(function() { + currentPortfolioItem.addClass('show'); + }, 100*l); + }); + } + + if(currentPortfolio.hasClass('slide_from_left')) { + currentPortfolio.find('article').each(function(i) { + var currentPortfolioItem = $j(this); + + setTimeout(function() { + currentPortfolioItem.addClass('show'); + }, (Math.random() * 200)); + }); + } + + if(currentPortfolio.hasClass('slide_from_top')) { + currentPortfolio.find('article').each(function(i) { + var currentPortfolioItem = $j(this); + setTimeout(function() { + currentPortfolioItem.addClass('show'); + }, timeArray[i]*50); + }); + } + + if(currentPortfolio.hasClass('diagonal_fade')) { + currentPortfolio.find('article').each(function(i) { + var currentPortfolioItem = $j(this); + setTimeout(function() { + currentPortfolioItem.addClass('show'); + }, timeArray[i]*50); + }); + } + initParallax(); + }, + onMixEnd: function(){ + initParallax(); + } + }); + }); + } +} + +/* + ** Init z-index for portfolio items + */ +function initPortfolioZIndex(){ + "use strict"; + + if($j('.projects_holder_outer.portfolio_no_space').length){ + $j('.no_space.hover_text article').each(function(i){ + $j(this).css('z-index', i +10); + }); + } +} + +function initPortfolioMasonry(){ + "use strict"; + + if($j('.projects_masonry_holder, .masonry_with_space').length){ + + $j('.projects_masonry_holder, .masonry_with_space .projects_holder').each(function(){ + var $window = jQuery(window); + var $this = $j(this); + $this.waitForImages(function(){ + $this.animate({opacity:1}); + if($j('.projects_masonry_holder').length){ + resizeMasonry($this); + } + $this.isotope({ + resizable: false, + itemSelector: '.portfolio_masonry_item, .mix', + layoutMode: 'masonry' + }).isotope( 'layout' ); + + if($j('.projects_masonry_holder').length){ + setPortfolioMasZIndex(); + $window.resize(function() {resizeMasonry($this); setPortfolioMasZIndex();}); + } + + if($this.hasClass('portfolio_one_by_one')) { + $this.find('article').each(function(l) { + var $this = $j(this); + setTimeout(function() { + $this.addClass('show'); + }, 100*l); + }); + } + + if($this.hasClass('portfolio_fade_from_bottom')) { + $this.find('article').each(function(l) { + $j(this).appear(function() { + $j(this).addClass('show'); + },{accX: 0, accY: -150}); + }); + } + }); + }); + } +} + +var portfolio_width; +function resizeMasonry(container){ + var $window = jQuery(window); + + if($j('.full_width').length){ + if($j('body').hasClass('vertical_menu_enabled') && $window_width > 1000){ + portfolio_width = $window.innerWidth() - $j('.vertical_menu_area').innerWidth(); + }else { + portfolio_width = $window.innerWidth(); + } + }else{ + var closest_container = container.closest('.container_inner'); + if(closest_container.has('.column_inner').length) { + portfolio_width = container.closest('.column_inner').innerWidth(); + } else { + portfolio_width = closest_container.innerWidth(); + } + } + + container.width(portfolio_width); + + if(container.hasClass('gs4')){ + var $cols = 4; + if(portfolio_width <= 1000 && portfolio_width > 480){ + $cols = 2; + }else if(portfolio_width <= 480){ + $cols = 1; + } + + } else{ + var $cols = 5; + if(portfolio_width > 1600){ + $cols = 5; + }else if(portfolio_width <= 1600 && portfolio_width > 1200){ + $cols = 4; + }else if(portfolio_width <= 1200 && portfolio_width > 1000){ + $cols = 3; + }else if(portfolio_width <= 1000 && portfolio_width > 480){ + $cols = 2; + }else if(portfolio_width <= 480){ + $cols = 1; + } + } + + var largeItemHeight; + if(container.find('article[class*="default"]:first img').height()){ + largeItemHeight = container.find('article[class*="default"]:first img').height(); + }else if(container.find('article[class*="large_width"]:not(.large_width_height):first img').height()){ + largeItemHeight = container.find('article[class*="large_width"]:not(.large_width_height):first img').height(); + }else{ + largeItemHeight = (container.find('article[class*="large_width_height"]:first img').height()) ? (container.find('article[class*="large_width_height"]:first img').height())/2 : (container.find('article[class*="large_height"]:first img').height())/2; + } + var double = ($window.innerWidth() > 480) ? 2 : 1 ; + container.find('article[class*="large_width_height"] img, article[class*="large_height"] img').css('height',(largeItemHeight*double)); + + container.isotope({ + masonry: { columnWidth: portfolio_width / parseInt($cols)} + }); + + +} + + +function setPortfolioMasZIndex(){ + var $elemXPos = {}; + var $elemZIndex = {}; + + $j('.projects_masonry_holder article').each(function(){ + $elemXPos[$j(this).index()] = getPortfolioXPos($j(this).css('left')); + }); + + var $elemXPosArray = $j.map($elemXPos, function (value) { return value; }); + $elemXPosArray = cleanPortfolioMasXArray($elemXPosArray); + $elemXPosArray.sort(function(x,y){return x-y}); + + for(var i = 0; i < $elemXPosArray.length; i++){ + $elemZIndex[$elemXPosArray[i]] = i*10; + } + + $j.each($elemXPos,function(key,val){ + + var $zi; + var $bgd = val; + $j.each($elemZIndex,function(key,val){ + if($bgd == key) { + $zi = val; + } + }); + + $j('.projects_masonry_holder article:eq('+key+')').css('z-index',$zi); + }); +} + + +function cleanPortfolioMasXArray($elemXPosArray) { + var i; + var length = $elemXPosArray.length; + var $elemXPosOutArray = []; + var tmp = {}; + + for (i = 0; i < length; i++) { + tmp[$elemXPosArray[i]] = 0; + } + for (i in tmp) { + $elemXPosOutArray.push(i); + } + return $elemXPosOutArray; +} + +function getPortfolioXPos(css) { + //return css.substr(7, css.length - 8).split(', ')[4]; + return css.substr(0, css.length - 2); +} + +function initPortfolioMasonryFilter(){ + + "use strict"; + var portfolioIsotopeAnimation = null; + $j('.filter:first').addClass('current'); + $j('.filter').click(function(){ + + clearTimeout(portfolioIsotopeAnimation); + $j('.isotope, .isotope .isotope-item').css('transition-duration','0.8s'); + portfolioIsotopeAnimation = setTimeout(function(){ $j('.isotope, .isotope .isotope-item').css('transition-duration','0s'); },700); + + var selector = $j(this).attr('data-filter'); + $j('.projects_masonry_holder, .masonry_with_space .projects_holder').isotope({ filter: selector }); + + $j(".filter").removeClass("current"); + $j(this).addClass("current"); + + setTimeout(setPortfolioMasZIndex(),700); + + return false; + }); + +} + +function initServiceAnimation(){ + "use strict"; + + if($j(".fade_in_circle_holder").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.fade_in_circle_holder').each(function(){ + $j(this).appear(function(){ + $j(this).addClass('animate_circle'); + },{accX: 0, accY: -200}); + }); + } +} + +function checkTitleToShowOrHide(){ + if($j('.title_outer.animate_title_area').length){ + var title_area_height = $j('.title_outer').data('height'); + if($scroll > $j('.title').height()){ + $j('.title_outer').css({'height':title_area_height, 'opacity':'1', 'overflow':'visible'}); + } + } +} + +/* +** Title area animation +*/ +function initTitleAreaAnimation(){ + if($j('.title_outer.animate_title_area').length){ + + var title_area_height = $j('.title_outer').data('height'); + if($j('.title_outer').hasClass('with_image')){ + title_area_height = $j('.image.responsive').height(); + } + if($scroll < $j('.title').height()){ + $j('.title_outer').animate({ height: title_area_height, opacity: 1}, 500, function(){ + $j(this).css({'overflow':'visible'}); + initPortfolioSingleInfo(); + if($j('nav.content_menu').length > 0){ + content_menu_position = $j('nav.content_menu').offset().top; + contentMenuPosition(); + } + }); + } + } +} + + +/* +** Title image with parallax effect +*/ +function initParallaxTitle(){ + "use strict"; + + if(($j('.title').length > 0) && ($j('.touch').length === 0)){ + + if($j('.title.has_fixed_background').length){ + + var $background_size_width = parseInt($j('.title.has_fixed_background').css('background-size').match(/\d+/)); + + var title_holder_height = $j('.title.has_fixed_background').height(); + var title_rate = (title_holder_height / 10000) * 7; + + var title_distance = $scroll - $j('.title.has_fixed_background').offset().top; + var title_bpos = -(title_distance * title_rate); + $j('.title.has_fixed_background').css({'background-position': 'center '+ (0+add_for_admin_bar) +'px' }); + if($j('.title.has_fixed_background').hasClass('zoom_out')){ + $j('.title.has_fixed_background').css({'background-size': $background_size_width-$scroll + 'px auto'}); + } + } + + $j(window).on('scroll', function() { + if($j('.title.has_fixed_background').length){ + + var title_distance = $scroll - $j('.title.has_fixed_background').offset().top; + + var title_bpos = -(title_distance * title_rate); + $j('.title.has_fixed_background').css({'background-position': 'center ' + (title_bpos+add_for_admin_bar) + 'px' }); + if($j('.title.has_fixed_background').hasClass('zoom_out')){ + $j('.title.has_fixed_background').css({'background-size': $background_size_width-$scroll + 'px auto'}); + } + } + }); + } +} + +/* + Plugin: jQuery Parallax + Version 1.1.3 + Author: Ian Lunn + Twitter: @IanLunn + Author URL: http://www.ianlunn.co.uk/ + Plugin URL: http://www.ianlunn.co.uk/plugins/jquery-parallax/ + + Dual licensed under the MIT and GPL licenses: + http://www.opensource.org/licenses/mit-license.php + http://www.gnu.org/licenses/gpl.html + */ + +(function( $ ){ + var $window = $(window); + var windowHeight = $window.height(); + + $window.resize(function () { + windowHeight = $window.height(); + }); + + $.fn.parallax = function(xpos, speedFactor, outerHeight) { + var $this = $(this); + var getHeight; + var firstTop; + var paddingTop = 0; + + //get the starting position of each element to have parallax applied to it + $this.each(function(){ + firstTop = $this.offset().top; + }); + + if (outerHeight) { + getHeight = function(jqo) { + return jqo.outerHeight(true); + }; + } else { + getHeight = function(jqo) { + return jqo.height(); + }; + } + + // setup defaults if arguments aren't specified + if (arguments.length < 1 || xpos === null) xpos = "50%"; + if (arguments.length < 2 || speedFactor === null) speedFactor = 0.1; + if (arguments.length < 3 || outerHeight === null) outerHeight = true; + + // function to be called whenever the window is scrolled or resized + function update(){ + var pos = $window.scrollTop(); + + $this.each(function(){ + var $element = $(this); + var top = $element.offset().top; + var height = getHeight($element); + + // Check if totally above or totally below viewport + if (top + height < pos || top > pos + windowHeight) { + return; + } + + $this.css('backgroundPosition', xpos + " " + Math.round((firstTop - pos) * speedFactor) + "px"); + }); + } + + $window.bind('scroll', update).resize(update); + update(); + }; +})(jQuery); + + +/* + ** Sections with parallax background image + */ +function initParallax(){ + "use strict"; + + if($j('.parallax_section_holder').length){ + $j('.parallax_section_holder').each(function() { + var speed = $j(this).data('speed')*0.4; + $j(this).parallax("50%", speed); + }); + } +} + +/* +** Smooth scroll functionality for Side Area +*/ +function initSideAreaScroll(){ + "use strict"; + + if($j('.side_menu').length){ + $j(".side_menu").niceScroll({ + scrollspeed: 60, + mousescrollstep: 40, + cursorwidth: 0, + cursorborder: 0, + cursorborderradius: 0, + cursorcolor: "transparent", + autohidemode: false, + horizrailenabled: false + }); + } +} + +/* + ** Smooth scroll functionality for Vertical Menu Area Toogle style + */ +function initVerticalAreaMenuScroll(){ + "use strict"; + + if($j('.vertical_menu_area.with_scroll').length){ + $j(".vertical_menu_area.with_scroll").niceScroll({ + scrollspeed: 60, + mousescrollstep: 40, + cursorwidth: 0, + cursorborder: 0, + cursorborderradius: 0, + cursorcolor: "transparent", + autohidemode: false, + horizrailenabled: false + }); + + } +} + +/* +** Load more portfolios +*/ +function loadMore(){ + "use strict"; + + var i = 1; + + $j('.load_more a').on('click', function(e) { + e.preventDefault(); + + var link = $j(this).attr('href'); + var $content = '.projects_holder'; + var $anchor = '.portfolio_paging .load_more a'; + var $next_href = $j($anchor).attr('href'); // Get URL for the next set of posts + var filler_num = $j('.projects_holder .filler').length; + + var load_more_holder = $j('.portfolio_paging'); + var loading_holder = $j('.portfolio_paging_loading'); + + load_more_holder.hide(); + loading_holder.show(); + + $j.get(link+'', function(data){ + $j('.projects_holder .filler').slice(-filler_num).remove(); + var $new_content = $j($content, data).wrapInner('').html(); // Grab just the content + $next_href = $j($anchor, data).attr('href'); // Get the new href + $j($content, data).waitForImages(function() { + + $j('article.mix:last').after($new_content); // Append the new content + + $j('.projects_holder article').css('visibility','visible'); + $j('article:not(.show)').each(function(l){ + $j(this).addClass('show'); + }); + + if($j('.masonry_with_space').length){ + $j('.masonry_with_space .projects_holder').isotope('reloadItems').isotope(); + }else{ + var min_height = $j('article.mix:first').height(); + $j('article.mix').css('min-height',min_height); + $j('.projects_holder').mixitup('remix','all'); + } + prettyPhoto(); + if($j('.load_more').attr('rel') > i) { + $j('.load_more a').attr('href', $next_href); // Change the next URL + } else { + $j('.load_more').remove(); + } + $j('.projects_holder .portfolio_paging:last').remove(); // Remove the original navigation + $j('article.mix').css('min-height',0); + + load_more_holder.show(); + loading_holder.hide(); + }); + + }); + i++; + }); +} + +/* +** Picture popup for portfolio lists and portfolio single +*/ +function prettyPhoto(){ + "use strict"; + + $j('a[data-rel]').each(function() { + $j(this).attr('rel', $j(this).data('rel')); + }); + + $j("a[rel^='prettyPhoto']").prettyPhoto({ + animation_speed: 'normal', /* fast/slow/normal */ + slideshow: false, /* false OR interval time in ms */ + autoplay_slideshow: false, /* true/false */ + opacity: 0.80, /* Value between 0 and 1 */ + show_title: true, /* true/false */ + allow_resize: true, /* Resize the photos bigger than viewport. true/false */ + horizontal_padding: 0, + default_width: 650, + default_height: 400, + counter_separator_label: '/', /* The separator for the gallery counter 1 "of" 2 */ + theme: 'pp_default', /* light_rounded / dark_rounded / light_square / dark_square / facebook */ + hideflash: false, /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */ + wmode: 'opaque', /* Set the flash wmode attribute */ + autoplay: true, /* Automatically start videos: True/False */ + modal: false, /* If set to true, only the close button will close the window */ + overlay_gallery: false, /* If set to true, a gallery will overlay the fullscreen image on mouse over */ + keyboard_shortcuts: true, /* Set to false if you open forms inside prettyPhoto */ + deeplinking: false, + social_tools: false + }); +} + +/* +** Show/Hide Mobile menu +*/ +function initMobileMenu(){ + "use strict"; + + $j(".mobile_menu_button > span").on('tap click', function(e){ + e.preventDefault(); + + if ($j(".mobile_menu > ul").is(":visible")){ + $j(".mobile_menu > ul").slideUp(200); + } else { + $j(".mobile_menu > ul").slideDown(200); + } + }); + + $j(".mobile_menu > ul > li.has_sub > span.mobile_arrow, .mobile_menu > ul > li.has_sub > h3, .mobile_menu > ul > li.has_sub > a[href*=#]").on('tap click', function(e){ + e.preventDefault(); + + if ($j(this).closest('li.has_sub').find("> ul.sub_menu").is(":visible")){ + $j(this).closest('li.has_sub').find("> ul.sub_menu").slideUp(200); + $j(this).closest('li.has_sub').removeClass('open_sub'); + } else { + $j(this).closest('li.has_sub').addClass('open_sub'); + $j(this).closest('li.has_sub').find("> ul.sub_menu").slideDown(200); + } + }); + + $j(".mobile_menu > ul > li.has_sub > ul.sub_menu > li.has_sub > span.mobile_arrow, .mobile_menu > ul > li.has_sub > ul.sub_menu > li.has_sub > h3, .mobile_menu > ul > li.has_sub > ul.sub_menu > li.has_sub > a[href*=#]").on('tap click', function(e){ + e.preventDefault(); + + if ($j(this).parent().find("ul.sub_menu").is(":visible")){ + $j(this).parent().find("ul.sub_menu").slideUp(200); + $j(this).parent().removeClass('open_sub'); + } else { + $j(this).parent().addClass('open_sub'); + $j(this).parent().find("ul.sub_menu").slideDown(200); + } + }); + + $j(".mobile_menu ul li > a, .q_logo a").on('click', function(){ + + if(($j(this).attr('href') !== "http://#") && ($j(this).attr('href') !== "#")){ + $j(".mobile_menu > ul").slideUp(); + } + }); +} + +/* +** Init flexslider for portfolio single +*/ +function initFlexSlider(){ + "use strict"; + $j('.flexslider').each(function(){ + var interval = 8000; + if(typeof $j(this).data('interval') !== 'undefined' && $j(this).data('interval') !== false) { + interval = parseFloat($j(this).data('interval')) * 1000; + } + + var slideshow = true; + if(interval === 0) { + slideshow = false; + } + + var animation = 'slide'; + if(typeof $j(this).data('flex_fx') !== 'undefined' && $j(this).data('flex_fx') !== false) { + animation = $j(this).data('flex_fx'); + } + + $j(this).flexslider({ + animationLoop: true, + controlNav: false, + useCSS: false, + pauseOnAction: true, + pauseOnHover: true, + slideshow: slideshow, + animation: animation, + prevText: "
", + nextText: "
", + animationSpeed: 600, + slideshowSpeed: interval, + start: function(){ + setTimeout(function(){$j(".flexslider").fitVids();},100); + } + }); + + $j('.flex-direction-nav a').click(function(e){ + e.preventDefault(); + e.stopImmediatePropagation(); + e.stopPropagation(); + }); + }); +} + +/* +** Init fitVideo function for responsive video files +*/ +function fitVideo(){ + "use strict"; + + $j(".portfolio_images").fitVids(); + $j(".video_holder").fitVids(); + $j(".format-video .post_image").fitVids(); + $j(".format-video .q_masonry_blog_post_image").fitVids(); +} + +/* +** Function for follow portfolio single descripton +*/ +var $scrollHeight; +function initPortfolioSingleInfo(){ + "use strict"; + + var $sidebar = $j(".portfolio_single_follow"); + if($j(".portfolio_single_follow").length > 0){ + + var offset = $sidebar.offset(); + $scrollHeight = $j(".portfolio_container").height(); + var $scrollOffset = $j(".portfolio_container").offset(); + var $window = $j(window); + + var $headerHeight = parseInt($j('header.page_header').css('height'), 10); + + $window.scroll(function() { + if($window.width() > 960){ + if ($window.scrollTop() + $headerHeight + 3 > offset.top) { + if ($window.scrollTop() + $headerHeight + $sidebar.height() + 24 < $scrollOffset.top + $scrollHeight) { + + $sidebar.stop().animate({ + marginTop: $window.scrollTop() - offset.top + $headerHeight + }); + } else { + $sidebar.stop().animate({ + marginTop: $scrollHeight - $sidebar.height() - 24 + }); + } + } else { + $sidebar.stop().animate({ + marginTop: 0 + }); + } + }else{ + $sidebar.css('margin-top',0); + } + }); + } +} + +/* +** Init tabs shortcodes +*/ +function initTabs(){ + "use strict"; + if($j('.q_tabs').length){ + $j('.q_tabs').appear(function() { + $j('.q_tabs').css('visibility', 'visible'); + },{accX: 0, accY: -100}); + var $tabsNav = $j('.tabs-nav'); + var $tabsNavLis = $tabsNav.children('li'); + $tabsNav.each(function() { + var $this = $j(this); + $this.next().children('.tab-content').stop(true,true).hide().first().show(); + $this.children('li').first().addClass('active').stop(true,true).show(); + }); + $tabsNavLis.on('click', function(e) { + var $this = $j(this); + $this.siblings().removeClass('active').end().addClass('active'); + $this.parent().next().children('.tab-content').stop(true,true).hide().siblings( $this.find('a').attr('href') ).fadeIn(); + e.preventDefault(); + }); + } +} + +/* + ** Init accordion and toogle shortcodes + */ +function initAccordion() { + "use strict"; + + if($j(".q_accordion_holder").length){ + $j(".q_accordion_holder").appear(function() { + $j(".q_accordion_holder").css('visibility', 'visible'); + },{accX: 0, accY: -100}); + + if ($j(".accordion").length) { + $j(".accordion").accordion({ + animate: "swing", + collapsible: true, + active: false, + icons: "", + heightStyle: "content", + activate: function(event, ui) { + initParallax(); + } + }); + + //define custom options for each accordion + $j(".accordion").each(function() { + var activeTab = parseInt($j(this).data('active-tab')); + if(activeTab !== "") { + activeTab = activeTab - 1; // - 1 because active tab is set in 0 index base + $j(this).accordion('option', 'active', activeTab); + } + var borderRadius = parseInt($j(this).data('border-radius')); + + if(borderRadius !== "") { + $j(this).find('.accordion_mark').css('border-radius', borderRadius+"px"); + } + var collapsible = ($j(this).data('collapsible') == 'yes') ? true : false; + $j(this).accordion('option', 'collapsible', collapsible); + $j(this).accordion('option', 'collapsible', collapsible); + }); + } + $j(".toggle").addClass("accordion ui-accordion ui-accordion-icons ui-widget ui-helper-reset") + .find(".title-holder") + .addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom") + .hover(function() { + $j(this).toggleClass("ui-state-hover"); + }) + .click(function() { + $j(this) + .toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom") + .next().toggleClass("ui-accordion-content-active").slideToggle(400); + return false; + }) + .next() + .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom") + .hide(); + + $j(".toggle").each(function() { + var activeTab = parseInt($j(this).data('active-tab')); + if(activeTab !== "" && activeTab >= 1) { + activeTab = activeTab - 1; // - 1 because active tab is set in 0 index base + $j(this).find('.ui-accordion-content').eq(activeTab).show(); + $j(this).find('.ui-accordion-header').eq(activeTab).addClass('ui-state-active'); //set active accordion header + } + + }); + } +} + +/* +** Function to enable link in accordion +*/ +function initAccordionContentLink(){ + "use strict"; + + if($j(".accordion").length){ + $j('.accordion_holder .accordion_inner .accordion_content a').click(function(){ + if($j(this).attr('target') === '_blank'){ + window.open($j(this).attr('href'),'_blank'); + }else{ + window.open($j(this).attr('href'),'_self'); + } + return false; + }); + } +} + +/* +** Init testimonials shortcode +*/ +function initTestimonials(){ + "use strict"; + + if($j('.testimonials_carousel').length){ + $j('.testimonials_carousel').each(function(){ + var interval = 5000; + if(typeof $j(this).data('auto-rotate-slides') !== 'undefined' && $j(this).data('auto-rotate-slides') !== false) { + interval = parseFloat($j(this).data('auto-rotate-slides')) * 1000; + } + + var slideshow = true; + if(interval === 0) { + slideshow = false; + } + + var animation = 'fade'; + if(typeof $j(this).data('animation-type') !== 'undefined' && $j(this).data('animation-type') !== false) { + animation = $j(this).data('animation-type'); + } + + var directionNav = true; + if(typeof $j(this).data('show-navigation') !== 'undefined') { + directionNav = $j(this).data('show-navigation') == 'no' ? false : true; + } + + var animationSpeed = 600; + if(typeof $j(this).data('animation-speed') !== 'undefined' && $j(this).data('animation-speed') !== false) { + animationSpeed = $j(this).data('animation-speed'); + } + + $j(this).flexslider({ + animationLoop: true, + controlNav: false, + directionNav: directionNav, + useCSS: false, + pauseOnAction: true, + pauseOnHover: false, + slideshow: slideshow, + animation: animation, + itemMargin: 25, + minItems: 1, + maxItems: 1, + animationSpeed: animationSpeed, + slideshowSpeed: interval, + start: function(slider){ + initParallax(); + } + }); + }); + + } +} + +/* +** Function to close message shortcode +*/ +function initMessages(){ + "use strict"; + + if($j('.q_message').length){ + $j('.q_message').each(function(){ + $j(this).find('.close').click(function(e){ + e.preventDefault(); + $j(this).parent().parent().fadeOut(500); + }); + }); + } +} +/* +** Init Element Animations +*/ +function initElementsAnimation(){ + "use strict"; + + if($j(".element_from_fade").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_from_fade').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_from_fade_on'); + },{accX: 0, accY: -100}); + }); + } + + if($j(".element_from_left").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_from_left').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_from_left_on'); + },{accX: 0, accY: -100}); + }); + } + + if($j(".element_from_right").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_from_right').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_from_right_on'); + },{accX: 0, accY: -100}); + }); + } + + if($j(".element_from_top").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_from_top').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_from_top_on'); + },{accX: 0, accY: -100}); + }); + } + + if($j(".element_from_bottom").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_from_bottom').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_from_bottom_on'); + },{accX: 0, accY: -100}); + }); + } + + if($j(".element_transform").length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.element_transform').each(function(){ + var $this = $j(this); + + $this.appear(function() { + $this.addClass('element_transform_on'); + },{accX: 0, accY: -100}); + }); + } +} + +/* +** Init audio player for blog layout +*/ +function fitAudio(){ + "use strict"; + + $j('audio.blog_audio').mediaelementplayer({ + audioWidth: '100%' + }); +} + +/* +** Init masonry layout for blog template +*/ +function initBlog() { + "use strict"; + + if($j('.blog_holder.masonry').length) { + var width_blog = $j(this).closest('.container_inner').width(); + if($j('.blog_holder.masonry').closest(".column_inner").length) { + width_blog = $j('.blog_holder.masonry').closest(".column_inner").width(); + } + $j('.blog_holder.masonry').width(width_blog); + var $container = $j('.blog_holder.masonry'); + + $container.waitForImages(function() { + setTimeout(function() { + $container.isotope({ + itemSelector: 'article', + resizable: false, + masonry: {columnWidth: '.blog_holder_grid_sizer', gutter: '.blog_holder_grid_gutter'} + }); + + $j('.blog_holder.masonry').animate({opacity: "1"}, 500); + }, 400); + }); + + $j('.filter').click(function() { + var selector = $j(this).attr('data-filter'); + $container.isotope({filter: selector}); + return false; + }); + + if($container.hasClass('masonry_infinite_scroll')) { + $container.infinitescroll({ + navSelector: '.blog_infinite_scroll_button span', + nextSelector: '.blog_infinite_scroll_button span a', + itemSelector: 'article', + loading: { + finishedMsg: finished_text, + msgText: loading_text + } + }, + // call Isotope as a callback + function(newElements) { + $container.isotope('appended', $j(newElements)); + fitVideo(); + fitAudio(); + initFlexSlider(); + setTimeout(function() { + $j('.blog_holder.masonry').isotope('layout'); + }, 400); + } + ); + } else if($container.hasClass('masonry_load_more')) { + + + var i = 1; + $j('.blog_load_more_button a').off('click tap').on('click tap', function(e) { + e.preventDefault(); + + var load_more_holder = $j('.blog_load_more_button'); + var load_more_loading = $j('.blog_load_more_button_loading'); + load_more_holder.hide(); + load_more_loading.show(); + + var link = $j(this).attr('href'); + var $content = '.masonry_load_more'; + var $anchor = '.blog_load_more_button a'; + var $next_href = $j($anchor).attr('href'); + $j.get(link + '', function(data) { + var $new_content = $j($content, data).wrapInner('').html(); + $next_href = $j($anchor, data).attr('href'); + $container.append($j($new_content)).isotope('reloadItems').isotope({sortBy: 'original-order'}); + fitVideo(); + fitAudio(); + initFlexSlider(); + setTimeout(function() { + $j('.blog_holder.masonry').isotope('layout'); + }, 400); + + load_more_holder.show(); + load_more_loading.hide(); + + if($j('.blog_load_more_button span').attr('rel') > i) { + $j('.blog_load_more_button a').attr('href', $next_href); // Change the next URL + } else { + $j('.blog_load_more_button').remove(); + } + }); + i++; + }); + + } + } +} + +/* + ** Init full width masonry layout for blog template + */ +function initBlogMasonryFullWidth(){ + "use strict"; + + if($j('.masonry_full_width').length){ + var width_blog = $j('.full_width_inner').width(); + + $j('.masonry_full_width').width(width_blog); + var $container = $j('.masonry_full_width'); + + $j('.filter').click(function(){ + var selector = $j(this).attr('data-filter'); + $container.isotope({ filter: selector }); + return false; + }); + if( $container.hasClass('masonry_infinite_scroll')){ + $container.infinitescroll({ + navSelector : '.blog_infinite_scroll_button span', + nextSelector : '.blog_infinite_scroll_button span a', + itemSelector : 'article', + loading: { + finishedMsg: finished_text, + msgText : loading_text + } + }, + // call Isotope as a callback + function( newElements ) { + $container.isotope( 'appended', $j( newElements ) ); + fitVideo(); + fitAudio(); + initFlexSlider(); + + setTimeout(function() { + $j('.blog_holder.masonry_full_width').isotope( 'layout'); + }, 400); + } + ); + }else if($container.hasClass('masonry_load_more')){ + + + var i = 1; + $j('.blog_load_more_button a').off('click tap').on('click tap', function(e) { + e.preventDefault(); + + var link = $j(this).attr('href'); + var $content = '.masonry_load_more'; + var $anchor = '.blog_load_more_button a'; + var $next_href = $j($anchor).attr('href'); + $j.get(link+'', function(data){ + var $new_content = $j($content, data).wrapInner('').html(); + $next_href = $j($anchor, data).attr('href'); + $container.append( $j( $new_content) ).isotope( 'reloadItems' ).isotope({ sortBy: 'original-order' }); + fitVideo(); + fitAudio(); + initFlexSlider(); + + setTimeout(function() { + $j('.blog_holder.masonry_full_width').isotope( 'layout'); + }, 400); + + if($j('.blog_load_more_button span').attr('rel') > i) { + $j('.blog_load_more_button a').attr('href', $next_href); // Change the next URL + } else { + $j('.blog_load_more_button').remove(); + } + + }); + i++; + }); + + } + + $container.waitForImages(function() { + setTimeout(function() { + $container.isotope({ + itemSelector: 'article', + resizable: false, + masonry: { columnWidth: '.blog_holder_grid_sizer',gutter: '.blog_holder_grid_gutter'} + }); + + $j('.masonry_full_width').animate({opacity: "1"}, 500); + }, 400); + }); + } +} + +/* + ** Min height for smaall image blog + */ +function initSmallImageBlogHeight(){ + "use strict"; + + if($j('.blog_small_image').length){ + $j('article').each(function() { + $j(this).find('.post_text_inner').css('min-height', $j(this).find('.post_image').height() - 46); //46 is top and bottom padding + }); + } +} + + +/* +** Init masonry layout for blog masonry shortcode +*/ +function initQBlog(){ + "use strict"; + + if($j('.q_masonry_blog').length){ + $j('.q_masonry_blog').each(function() { + var width_blog; + width_blog = $j(this).parents('.container_inner').width(); + if($j('.full_width').length && $j(this).parents('.grid_section').length == 0){ + width_blog = $j('.full_width').width(); + }else{ + if($j(this).parents(".column_inner").length) { + width_blog = $j(this).parents(".column_inner").width(); + } + } + + $j(this).width(width_blog); + var $container = $j(this); + var $cols = 3; + if($j('.full_width').length && $j(this).parents('.grid_section').length == 0){ + if($container.width() < 480) { + $cols = 1; + } else if($container.width() <= 703) { + $cols = 2; + } else if($container.width() <= 920) { + $cols = 3; + } else if($container.width() <= 1320) { + $cols = 4; + } else{ + $cols = 5; + } + } else{ + if($container.width() < 420) { + $cols = 1; + } else if($container.width() <= 805) { + $cols = 2; + } + } + $container.isotope({ + itemSelector: 'article', + resizable: false, + masonry: { columnWidth: $j('.q_masonry_blog').width() / $cols } + }); + $j(window).resize(function(){ + + if($j('.full_width').length && $j(this).parents('.grid_section').length == 0){ + if($container.width() < 480) { + $cols = 1; + } else if($container.width() <= 703) { + $cols = 2; + } else if($container.width() <= 920) { + $cols = 3; + } else if($container.width() <= 1320) { + $cols = 4; + } else { + $cols = 5; + } + } else{ + if($container.width() < 420) { + $cols = 1; + } else if($container.width() <= 785) { + $cols = 2; + } else { + $cols = 3; + } + } + $container.isotope({ + masonry: { columnWidth: $container.width() / $cols} + }); + }); + $j(this).animate({opacity: "1"}, 500); + }); + } +} + +/* +** Init progress bar with icon +*/ +var timeOuts = []; +function initProgressBarsIcon(){ + "use strict"; + + if($j('.q_progress_bars_icons_holder').length){ + $j('.q_progress_bars_icons_holder').each(function() { + var $this = $j(this); + $this.appear(function() { + $this.find('.q_progress_bars_icons').css('opacity','1'); + $this.find('.q_progress_bars_icons').each(function() { + var number = $j(this).find('.q_progress_bars_icons_inner').data('number'); + var size = $j(this).find('.q_progress_bars_icons_inner').data('size'); + + if(size !== ""){ + $j(this).find('.q_progress_bars_icons_inner.custom_size .bar').css({'width': size+'px','height':size+'px'}); + $j(this).find('.q_progress_bars_icons_inner.custom_size .bar .fa-stack').css({'font-size': size/2+'px'}); + } + + var bars = $j(this).find('.bar'); + + bars.each(function(i){ + if(i < number){ + var time = (i + 1)*150; + timeOuts[i] = setTimeout(function(){ + $j(bars[i]).addClass('active'); + },time); + } + }); + }); + },{accX: 0, accY: -200}); + }); + } +} + +(function( $ ){ + "use strict"; + + var $window = $(window); + $.fn.masonryParallax = function(speedFactor, outerHeight, startPosition) { + var $this = $(this); + var getHeight; + var firstTop; + var startPositionAdd = 0; + + //get the starting position of element to have parallax applied to it + firstTop = $this.offset().top; + + //get the height element + if (outerHeight) { + getHeight = function(jqo) { + return jqo.outerHeight(true); + }; + } else { + getHeight = function(jqo) { + return jqo.height(); + }; + } + + //get type so elements could take it's initial position + if(startPosition != 0){ + startPositionAdd = startPosition; + } + + // setup defaults if arguments aren't specified + if (arguments.length < 1 || speedFactor === null) speedFactor = 0.1; + if (arguments.length < 2 || outerHeight === null) outerHeight = true; + + // function to be called whenever the window is scrolled or resized + var top = $this.offset().top; + var height = getHeight($this); + function update(){ + // Check if totally above or totally below viewport + if (top + height < $scroll || top > $scroll + $window_height) { + return; + } + $this.css('transform', 'translate3d(0px, '+ (Math.round((firstTop - height - $scroll) * speedFactor + startPositionAdd)) +'px, 0px)'); + } + + $window.bind('scroll', update).resize(update); + update(); + }; +})(jQuery); + +/** + * Masonry gallery, init masonry and resize pictures in grid + */ +function initMasonryGallery(){ + "use strict"; + + resizeMasonryGallery($j('.grid-sizer').width()); + + if($j('.masonry_gallery_holder').length){ + + $j('.masonry_gallery_holder').each(function(){ + var $this = $j(this); + $this.waitForImages(function(){ + $this.animate({opacity:1}); + $this.isotope({ + itemSelector: '.masonry_gallery_item', + masonry: { + columnWidth: '.grid-sizer' + } + }); + + $this.find('.masonry_gallery_item.parallax_item').each(function(i){ + $j(this).masonryParallax($this.data('parallax_item_speed'), true, $this.data('parallax_item_offset')); + + }); + }); + }); + $j(window).resize(function(){ + resizeMasonryGallery($j('.grid-sizer').width()); + $j('.masonry_gallery_holder').isotope('reloadItems'); + }); + } +} + +function resizeMasonryGallery(size){ + "use strict"; + + var rectangle_portrait = $j('.masonry_gallery_holder .rectangle_portrait'); + var rectangle_landscape = $j('.masonry_gallery_holder .rectangle_landscape'); + var square_big = $j('.masonry_gallery_holder .square_big'); + var square_small = $j('.masonry_gallery_holder .square_small'); + + rectangle_portrait.css('height', 2*size); + if (window.innerWidth < 600) { + rectangle_landscape.css('height', size/2); + } + else { + rectangle_landscape.css('height', size); + } + square_big.css('height', 2*size); + if (window.innerWidth < 600) { + square_big.css('height', square_big.width()); + } + square_small.css('height', size); +} + +/* +** Init more facts shortcode +*/ +function initMoreFacts(){ + "use strict"; + + if($j('.more_facts_holder').length){ + $j('.more_facts_holder').each(function(){ + var $this = $j(this); + + var $more_label = 'More Facts'; + + if($j(this).find('.more_facts_button').data('morefacts') !== ""){ + $more_label = $j(this).find('.more_facts_button').data('morefacts'); + } + + var $less_label = 'Less Facts'; + + if($j(this).find('.more_facts_button').data('lessfacts') !== ""){ + $less_label = $j(this).find('.more_facts_button').data('lessfacts'); + } + + var height = $this.find('.more_facts_inner').height() + 70; + + var speed; + if(height > 0 && height < 601){ + speed = 800; + } else if(height > 600 && height < 1201){ + speed = 1500; + } else{ + speed = 2100; + } + $this.find('.more_facts_outer').css({'height':'0px','display':'none','opacity':'0'}); + + $this.find('.more_facts_button').on("mouseenter",function(){ + $j(this).css('color',$j(this).data('hovercolor')); + }).on("mouseleave",function() { + if(!$this.find('.more_facts_outer').is(':visible')){ + $j(this).css('color',$j(this).data('color')); + } + }); + + $this.find('.more_facts_button').click(function(){ + if(!$this.find('.more_facts_outer').is(':visible')){ + $this.find('.more_facts_fake_arrow').fadeIn(speed); + $this.addClass('more_fact_opened'); + $j(this).parent().parent().find('.more_facts_outer').css({'display':'block','opacity':'1'}).stop().animate({'height': height+30}, speed, function() { + if($j('.parallax_section_holder').length) { + initParallax(); + } + }); + $j(this).find('.more_facts_button_text').text($less_label); + $j(this).find('.more_facts_button_arrow').addClass('rotate_arrow'); + } else { + $this.find('.more_facts_fake_arrow').fadeOut(speed); + $j(this).parent().parent().find('.more_facts_outer').stop().animate({'height': '0px'}, speed,function(){ + $j(this).css({'display':'none','opacity':'0'}); + + if(!$this.find('.more_facts_button').is(":hover")){$this.find('.more_facts_button').css('color',$this.find('.more_facts_button').data('color'));} + $this.removeClass('more_fact_opened'); + + if($j('.parallax_section_holder').length) { + initParallax(); + } + }); + $j(this).find('.more_facts_button_text').text($more_label); + $j(this).find('.more_facts_button_arrow').removeClass('rotate_arrow'); + } + }); + }); + } +} + +/* +** Replace plceholder +*/ +function placeholderReplace(){ + "use strict"; + + $j('#contact-form [placeholder]').focus(function() { + var input = $j(this); + if (input.val() === input.attr('placeholder')) { + if (this.originalType) { + this.type = this.originalType; + delete this.originalType; + } + input.val(''); + input.removeClass('placeholder'); + } + }).blur(function() { + var input = $j(this); + if (input.val() === '') { + if (this.type === 'password') { + this.originalType = this.type; + this.type = 'text'; + } + input.addClass('placeholder'); + input.val(input.attr('placeholder')); + } + }).blur(); + + $j('#contact-form [placeholder]').parents('form').submit(function () { + $j(this).find('[placeholder]').each(function () { + var input = $j(this); + if (input.val() === input.attr('placeholder')) { + input.val(''); + } + }); + }); +} + +function totop_button(a) { + "use strict"; + + var b = $j("#back_to_top"); + b.removeClass("off on"); + if (a === "on") { b.addClass("on"); } else { b.addClass("off"); } +} + +function backButtonShowHide(){ + "use strict"; + + $j(window).scroll(function () { + var b = $j(this).scrollTop(); + var c = $j(this).height(); + var d; + if (b > 0) { d = b + c / 2; } else { d = 1; } + if (d < 1e3) { totop_button("off"); } else { totop_button("on"); } + }); +} + +function backToTop(){ + "use strict"; + + $j(document).on('click','#back_to_top',function(e){ + e.preventDefault(); + + $j('body,html').animate({scrollTop: 0}, $j(window).scrollTop()/3, 'linear'); + }); +} + +/* + ** Init steps + */ +function initSteps(){ + "use strict"; + if($j('.q_steps_holder').length){ + $j('.q_steps_holder').each(function(){ + $j(this).appear(function() { + $j(this).addClass('show'); + },{accX: 0, accY: -200}); + }); + } +} + +/* + ** Init message height + */ +function initMessageHeight(){ + "use strict"; + if($j('.q_message.with_icon').length){ + $j('.q_message.with_icon').each(function(){ + if($j(this).find('.message_text_holder').height() > $j(this).find('.q_message_icon_holder').height()) { + $j(this).find('.q_message_icon_holder').height($j(this).find('.message_text').height()); + } else { + $j(this).find('.message_text').height($j(this).find('.q_message_icon_holder').height()); + } + }); + } +} + +/** + * Init image hover + */ +function initImageHover() { + "use strict"; + if($j('.image_hover').length){ + $j('.image_hover').each(function(){ + $j(this).appear(function() { + + var default_visible_time = 300; + var transition_delay = $j(this).attr('data-transition-delay'); + var real_transition_delay = default_visible_time + parseFloat(transition_delay); + var object = $j(this); + + //wait for other hovers to complete + setTimeout(function() { + object.addClass('show'); + }, parseFloat(transition_delay)); + + //hold that image a little, than remove class + setTimeout(function() { + object.removeClass('show'); + }, real_transition_delay); + + },{accX: 0, accY: -200}); + }); + } +} + +/* + * Initializes vertical progress bars + */ +function initProgressBarsVertical(){ + "use strict"; + + if($j('.q_progress_bars_vertical').length){ + $j('.q_progress_bars_vertical').each(function() { + $j(this).appear(function() { + initToCounterVerticalProgressBar($j(this)); + var percentage = $j(this).find('.progress_content').data('percentage'); + $j(this).find('.progress_content').css('height', '0%'); + $j(this).find('.progress_content').animate({ + height: percentage+'%' + }, 1500); + },{accX: 0, accY: -200}); + }); + } +} + +/* + * Initializes vertical progress bar count to max value + */ +function initToCounterVerticalProgressBar($this){ + "use strict"; + + if($this.find('.progress_number span').length){ + $this.find('.progress_number span').each(function() { + var $max = parseFloat($j(this).text()); + $j(this).countTo({ + from: 0, + to: $max, + speed: 1500, + refreshInterval: 50 + }); + }); + } +} + +/* +* Check if there is anchor on load and scroll to it +*/ +function checkAnchorOnLoad(){ + "use strict"; + + var hash = window.location.hash; + var paspartuScrollAdd = $j('body').hasClass('paspartu_on_top_fixed') ? $window_width*paspartu_width : 0; + var scrollToAmount; + var top_header_height; + if(hash !== "" && $j('[data-q_id="'+hash+'"]').length > 0){ + if($j('header.page_header').hasClass('fixed') && !$j('body').hasClass('vertical_menu_enabled')){ + if($j('header.page_header').hasClass('scroll_top')){ + top_header_height = header_top_height; + }else{ + top_header_height = 0; + } + + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if(header_height - ($j('[data-q_id="' + hash + '"]').offset().top + top_header_height)/4 >= min_header_height_scroll){ + var diff_of_header_and_section = $j('[data-q_id="' + hash + '"]').offset().top - header_height - paspartuScrollAdd; + scrollToAmount = diff_of_header_and_section + (diff_of_header_and_section/4) + (diff_of_header_and_section/16) + (diff_of_header_and_section/64) + 1; //several times od dividing to minimize the error, because fixed header is shrinking while scroll, 1 is just to ensure + }else{ + if($j('header.page_header').hasClass('centered_logo')){ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_scroll - logo_height - 30 - paspartuScrollAdd; //30 is top/bottom margin of logo + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_scroll - paspartuScrollAdd; + } + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + + } else if($j('header.page_header').hasClass('fixed_top_header') && !$j('body').hasClass('vertical_menu_enabled')){ + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')){ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - header_top_height - paspartuScrollAdd; + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + + } else if($j('header.page_header').hasClass('fixed_hiding') && !$j('body').hasClass('vertical_menu_enabled')){ + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if ($j('[data-q_id="' + hash + '"]').offset().top - (header_height + logo_height / 2 + 40) <= scroll_amount_for_fixed_hiding) { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - header_height - logo_height / 2 - 40 - paspartuScrollAdd; //40 is top/bottom margin of logo + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_fixed_hidden - 40 - paspartuScrollAdd; //40 is top/bottom margin of logo + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + }else if($j('header.page_header').hasClass('stick') || $j('header.page_header').hasClass('stick_with_left_right_menu') && !$j('body').hasClass('vertical_menu_enabled')) { + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if (sticky_amount >= $j('[data-q_id="' + hash + '"]').offset().top) { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top + 1 - paspartuScrollAdd; // 1 is to show sticky menu + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_sticky - paspartuScrollAdd; + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + } else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + $j('html, body').animate({ + scrollTop: Math.round(scrollToAmount) + }, 1500, function() {}); + } + + //remove active state on anchors if section is not visible + $j(".main_menu a, .vertical_menu a, .mobile_menu a").each(function(){ + var i = $j(this).prop("hash"); + if(i !== "" && ($j('[data-q_id="' + i + '"]').length > 0) && ($j('[data-q_id="' + i + '"]').offset().top >= $window_height) && $scroll === 0){ + $j(this).parent().removeClass('active'); + $j(this).removeClass('current'); + } + }); +} + +/* +* Check active state of anchor links on scroll +*/ + +function changeActiveState(id){ + "use strict"; + + $j('.main_menu a').parent().removeClass('active'); + + $j(".main_menu a").each(function(){ + var i = $j(this).prop("hash"); + if(i === id){ + if($j(this).closest('.second').length === 0){ + $j(this).parent().addClass('active'); + }else{ + $j(this).closest('.second').parent().addClass('active'); + } + $j('.main_menu a').removeClass('current'); + $j(this).addClass('current'); + } + }); + + $j('.vertical_menu a').parent().removeClass('active'); + + $j(".vertical_menu a").each(function(){ + var i = $j(this).prop("hash"); + if(i === id){ + if($j(this).closest('.second').length === 0){ + $j(this).parent().addClass('active'); + }else{ + $j(this).closest('.second').parent().addClass('active'); + } + $j('.vertical_menu a').removeClass('current'); + $j(this).addClass('current'); + } + }); + + $j('.mobile_menu a').parent().removeClass('active'); + + $j(".mobile_menu a").each(function(){ + var i = $j(this).prop("hash"); + if(i === id){ + if($j(this).closest('.sub_menu').length === 0){ + $j(this).parent().addClass('active'); + }else{ + $j(this).closest('.sub_menu').parent().addClass('active'); + } + $j('.mobile_menu a').removeClass('current'); + $j(this).addClass('current'); + } + }); +} + +/* +* Check active state of anchor links on scroll +*/ +function checkAnchorOnScroll(){ + "use strict"; + + if($j('[data-q_id]').length && !$j('header.page_header').hasClass('regular')){ + $j('[data-q_id]').waypoint( function(direction) { + if(direction === 'down') { + changeActiveState($j(this).data("q_id")); + } + }, { offset: '50%' }); + + $j('[data-q_id]').waypoint( function(direction) { + if(direction === 'up') { + changeActiveState($j(this).data("q_id")); + } + }, { offset: function(){ + return -($j(this).outerHeight() - 150); + } }); + } +} + +/* +* Init scroll to section link if that link has hash value +*/ +function initHashClick(){ + "use strict"; + + var $doc = $j('html, body'); + var paspartuScrollAdd = $j('body').hasClass('paspartu_on_top_fixed') ? $window_width*paspartu_width : 0; + var scrollToAmount; + $j(document).on( "click", ".main_menu a, .vertical_menu a, .qbutton:not(.contact_form_button), .anchor, .widget li.anchor a", function(){ + var $this = $j(this); + var hash = $j(this).prop("hash"); + var top_header_height; + if((hash !== "" && $j(this).attr('href').split('#')[0] === "") || (hash !== "" && $j(this).attr('href').split('#')[0] !== "" && hash === window.location.hash) || (hash !== "" && $j(this).attr('href').split('#')[0] === window.location.href.split('#')[0])){ //in third condition 'hash !== ""' stays to prevent reload of page when link is active and ajax enabled + if($j('header.page_header').hasClass('fixed') && !$j('body').hasClass('vertical_menu_enabled')){ + if($j('header.page_header').hasClass('scroll_top')){ + top_header_height = header_top_height; + }else{ + top_header_height = 0; + } + + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if (header_height - ($j('[data-q_id="' + hash + '"]').offset().top + top_header_height) / 4 >= min_header_height_scroll) { + var diff_of_header_and_section = $j('[data-q_id="' + hash + '"]').offset().top - header_height - paspartuScrollAdd; + scrollToAmount = diff_of_header_and_section + (diff_of_header_and_section / 4) + (diff_of_header_and_section / 16) + (diff_of_header_and_section / 64) + 1; //several times od dividing to minimize the error, because fixed header is shrinking while scroll, 1 is just to ensure + } else { + if($j('header.page_header').hasClass('centered_logo')){ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_scroll - logo_height - paspartuScrollAdd - 30; //30 is top/bottom margin of logo + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_scroll - paspartuScrollAdd; + } + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + + } + } else if($j('header.page_header').hasClass('fixed_top_header') && !$j('body').hasClass('vertical_menu_enabled')){ + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')){ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - header_top_height - paspartuScrollAdd; + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + } else if($j('header.page_header').hasClass('fixed_hiding') && !$j('body').hasClass('vertical_menu_enabled')){ + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if ($j('[data-q_id="' + hash + '"]').offset().top - (header_height + logo_height / 2 + 40) <= scroll_amount_for_fixed_hiding) { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - header_height - logo_height / 2 - 40 - paspartuScrollAdd; //40 is top/bottom margin of logo + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_fixed_hidden - 40 - paspartuScrollAdd; //40 is top/bottom margin of logo + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + }else if($j('header.page_header').hasClass('stick') || $j('header.page_header').hasClass('stick_with_left_right_menu') && !$j('body').hasClass('vertical_menu_enabled')) { + if(!$j('header.page_header').hasClass('transparent') || $j('header.page_header').hasClass('scrolled_not_transparent')) { + if (sticky_amount >= $j('[data-q_id="' + hash + '"]').offset().top) { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top + 1 - paspartuScrollAdd; // 1 is to show sticky menu + } else { + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - min_header_height_sticky - paspartuScrollAdd; + } + }else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + } else{ + scrollToAmount = $j('[data-q_id="' + hash + '"]').offset().top - paspartuScrollAdd; + } + + + if($j('[data-q_id="'+hash+'"]').length > 0){ + $doc.stop().animate({ + scrollTop: Math.round(scrollToAmount) + }, 1500, function() { + anchorActiveState($this); + }); + + } + + if(history.pushState) { + history.pushState(null, null, hash); + } + return false; + } + + }); + $j(document).on( "click", ".mobile_menu a", function(){ + var $this = $j(this); + var hash = $j(this).prop("hash"); + if((hash !== "" && $j(this).attr('href').split('#')[0] === "") || (hash !== "" && $j(this).attr('href').split('#')[0] !== "" && hash === window.location.hash) || (hash !== "" && $j(this).attr('href').split('#')[0] === window.location.href.split('#')[0])){ //in third condition 'hash !== ""' stays to prevent reload of page when link is active and ajax enabled + + if($j('[data-q_id="'+hash+'"]').length > 0){ + $doc.animate({ + scrollTop: Math.round($j('[data-q_id="'+hash+'"]').offset().top - $j('.mobile_menu').height()) + }, 500,function(){ + anchorActiveState($this); + }); + + } + if(history.pushState) { + history.pushState(null, null, hash); + } + return false; + } + + }); +} + +/* +** Add class to items in last row in clients shortcode +*/ +function countClientsPerRow(){ + "use strict"; + + if($j('.qode_clients').length){ + + $j('.qode_clients').each(function() { + var $clients = $j(this); + var qode_clients_height = $clients.height(); + var qode_clients_width = $clients.width(); + var maxHeightClient; + var clientWidth = $clients.find('.qode_client_holder').width(); + var countClient = $clients.find('.qode_client_holder').length; + $clients.find('.qode_client_holder').each(function() { + maxHeightClient = maxHeightClient > $j(this).height() ? maxHeightClient : $j(this).height(); + }); + maxHeightClient = maxHeightClient + 35; //margin for client is 35 + var numberOfRows = Math.ceil(qode_clients_height / maxHeightClient); + var numberOfClientsPerRow = Math.ceil(qode_clients_width/clientWidth); + var numberOffullRows = Math.floor(countClient / numberOfClientsPerRow); + var numberOfClientsInLastRow = countClient - (numberOfClientsPerRow * numberOffullRows); + if(numberOfClientsInLastRow === 0){ + numberOfClientsInLastRow = numberOfClientsPerRow; + } + $clients.find( ".qode_client_holder" ).removeClass('border-bottom-none'); + var item_start_from = countClient - numberOfClientsInLastRow - 1; + $clients.find( ".qode_client_holder:gt("+ item_start_from +")" ).addClass('border-bottom-none'); + }); + } +} + +/* +** Calculate height for animated text icon shortcode +*/ +function animatedTextIconHeight(){ + "use strict"; + + if($j('.animated_icons_with_text').length){ + var $icons = $j('.animated_icons_with_text'); + var maxHeight; + + $icons.find('.animated_text p').each(function() { + maxHeight = maxHeight > $j(this).height() ? maxHeight : $j(this).height(); + }); + + if(maxHeight < 155) { + maxHeight = 155; + + } + $icons.find('.animated_icon_with_text_inner').height(maxHeight); + } +} + +/* +** Add class to items in last row in animated text icon shortcode +*/ +function countAnimatedTextIconPerRow(){ + "use strict"; + + if($j('.animated_icons_with_text').length){ + $j('.animated_icons_with_text').each(function() { + var $icons = $j(this); + var qode_icons_height = $icons.height(); + var qode_icons_width = $icons.width(); + var maxHeightIcons; + var iconWidth = $icons.find('.animated_icon_with_text_holder').width() + 1; // 1px because safari round on smaller number + var countIcons = $icons.find('.animated_icon_with_text_holder').length; + $icons.find('.animated_icon_with_text_holder').each(function() { + maxHeightIcons = maxHeightIcons > $j(this).height() ? maxHeightIcons : $j(this).height(); + }); + maxHeightIcons = maxHeightIcons + 30; //margin for client is 30 + var numberOfIconsPerRow = Math.ceil((qode_icons_width/iconWidth)); + var numberOffullRows = Math.floor(countIcons / numberOfIconsPerRow); + var numberOfIconsInLastRow = countIcons - (numberOfIconsPerRow * numberOffullRows); + if(numberOfIconsInLastRow === 0){ + numberOfIconsInLastRow = numberOfIconsPerRow; + } + $icons.find( ".animated_icon_with_text_holder" ).removeClass('border-bottom-none'); + var item_start_from = countIcons - numberOfIconsInLastRow - 1; + $icons.find( ".animated_icon_with_text_holder:gt("+ item_start_from +")" ).addClass('border-bottom-none'); + }); + } +} + + +/* +* Set active state in maim menu on anchor click +*/ + +function anchorActiveState(me){ + if(me.closest('.main_menu').length > 0){ + $j('.main_menu a').parent().removeClass('active'); + } + + if(me.closest('.vertical_menu').length > 0){ + $j('.vertical_menu a').parent().removeClass('active'); + } + + if(me.closest('.second').length === 0){ + me.parent().addClass('active'); + }else{ + me.closest('.second').parent().addClass('active'); + } + if(me.closest('.mobile_menu').length > 0){ + $j('.mobile_menu a').parent().removeClass('active'); + me.parent().addClass('active'); + } + + $j('.mobile_menu a, .main_menu a, .vertical_menu a').removeClass('current'); + me.addClass('current'); +} + +/* +** Video background initialization +*/ +function initVideoBackground(){ + "use strict"; + + $j('.video-wrap .video').mediaelementplayer({ + enableKeyboard: false, + iPadUseNativeControls: false, + pauseOtherPlayers: false, + // force iPhone's native controls + iPhoneUseNativeControls: false, + // force Android's native controls + AndroidUseNativeControls: false + }); + + //mobile check + if(navigator.userAgent.match(/(Android|iPod|iPhone|iPad|IEMobile|Opera Mini)/)){ + initVideoBackgroundSize(); + $j('.mobile-video-image').show(); + $j('.video-wrap').remove(); + } +} + +/* +** Calculate video background size +*/ +function initVideoBackgroundSize(){ + "use strict"; + + $j('.section .video-wrap').each(function(i){ + + var $sectionWidth = $j(this).closest('.section').outerWidth(); + $j(this).width($sectionWidth); + + var $sectionHeight = $j(this).closest('.section').outerHeight(); + min_w = vid_ratio * ($sectionHeight+20); + $j(this).height($sectionHeight); + + var scale_h = $sectionWidth / video_width_original; + var scale_v = ($sectionHeight - header_height) / video_height_original; + var scale = scale_v; + if (scale_h > scale_v) + scale = scale_h; + if (scale * video_width_original < min_w) {scale = min_w / video_width_original;} + + $j(this).find('video, .mejs-overlay, .mejs-poster').width(Math.ceil(scale * video_width_original +2)); + $j(this).find('video, .mejs-overlay, .mejs-poster').height(Math.ceil(scale * video_height_original +2)); + $j(this).scrollLeft(($j(this).find('video').width() - $sectionWidth) / 2); + $j(this).find('.mejs-overlay, .mejs-poster').scrollTop(($j(this).find('video').height() - ($sectionHeight)) / 2); + $j(this).scrollTop(($j(this).find('video').height() - ($sectionHeight)) / 2); + }); + + $j('.carousel .item .video .video-wrap').each(function(i){ + + var $slideWidth = $j(window).width(); + $j(this).width($slideWidth); + + var mob_header = $j(window).width() < 1000 ? $j('header.page_header').height() - 6 : 0; // 6 is because of the display: inline-block + var $slideHeight = $j(this).closest('.carousel.slide').height() - mob_header; + + min_w = vid_ratio * ($slideHeight+20); + $j(this).height($slideHeight); + + var scale_h = $slideWidth / video_width_original; + var scale_v = ($slideHeight - header_height) / video_height_original; + var scale = scale_v; + if (scale_h > scale_v) + scale = scale_h; + if (scale * video_width_original < min_w) {scale = min_w / video_width_original;} + + $j(this).find('video, .mejs-overlay, .mejs-poster').width(Math.ceil(scale * video_width_original +2)); + $j(this).find('video, .mejs-overlay, .mejs-poster').height(Math.ceil(scale * video_height_original +2)); + $j(this).scrollLeft(($j(this).find('video').width() - $slideWidth) / 2); + $j(this).find('.mejs-overlay, .mejs-poster').scrollTop(($j(this).find('video').height() - ($slideHeight)) / 2); + $j(this).scrollTop(($j(this).find('video').height() - ($slideHeight)) / 2); + }); + + $j('.portfolio_single .video .video-wrap, .blog_holder .video .video-wrap').each(function(i){ + + var $this = $j(this); + + var $videoWidth = $j(this).closest('.video').outerWidth(); + $j(this).width($videoWidth); + var $videoHeight = ($videoWidth*9)/16; + + if(navigator.userAgent.match(/(Android|iPod|iPhone|iPad|IEMobile|Opera Mini)/)){ + $this.parent().width($videoWidth); + $this.parent().height($videoHeight); + } + + min_w = vid_ratio * ($videoHeight+20); + $j(this).height($videoHeight); + + var scale_h = $videoWidth / video_width_original; + var scale_v = ($videoHeight - header_height) / video_height_original; + var scale = scale_v; + if (scale_h > scale_v) + scale = scale_h; + if (scale * video_width_original < min_w) {scale = min_w / video_width_original;} + + $j(this).find('video, .mejs-overlay, .mejs-poster').width(Math.ceil(scale * video_width_original +2)); + $j(this).find('video, .mejs-overlay, .mejs-poster').height(Math.ceil(scale * video_height_original +2)); + $j(this).scrollLeft(($j(this).find('video').width() - $videoWidth) / 2); + $j(this).find('.mejs-overlay, .mejs-poster').scrollTop(($j(this).find('video').height() - ($videoHeight)) / 2); + $j(this).scrollTop(($j(this).find('video').height() - ($videoHeight)) / 2); + }); + +} + +/* +** Icon With Text animation effect +*/ +function initIconWithTextAnimation(){ + "use strict"; + if($j('.q_icon_animation').length > 0 && $j('.no_animation_on_touch').length === 0){ + $j('.q_icon_animation').each(function(){ + $j(this).appear(function() { + $j(this).addClass('q_show_animation'); + },{accX: 0, accY: -200}); + }); + } +} + +/* +** Add class on body if browser is Safari +*/ +function initCheckSafariBrowser(){ + "use strict"; + + if (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) { + $j('body').addClass('safari_browser'); + } +} + +/* +** Initialize Qode search form +*/ +function initSearchButton(){ + + if($j('.search_slides_from_window_top').length){ + $j('.search_slides_from_window_top').click(function(e){ + e.preventDefault(); + + if($j('html').hasClass('touch')){ + if ($j('.qode_search_form').height() == "0") { + $j('.qode_search_form input[type="text"]').onfocus = function () { + window.scrollTo(0, 0); + document.body.scrollTop = 0; + }; + $j('.qode_search_form input[type="text"]').onclick = function () { + window.scrollTo(0, 0); + document.body.scrollTop = 0; + }; + $j('.header_top_bottom_holder').css('top','50px'); + $j('.qode_search_form').css('height','50px'); + $j('.content_inner').css('margin-top','50px'); + if($scroll < 34){ $j('header.page_header').css('top','0'); } + } else { + $j('.qode_search_form').css('height','0'); + $j('.header_top_bottom_holder').css('top','0'); + $j('.content_inner').css('margin-top','0'); + if($scroll < 34){ $j('header.page_header').css('top',-$scroll);} + } + + $j(window).scroll(function() { + if ($j('.qode_search_form').height() != "0" && $scroll > 50) { + $j('.qode_search_form').css('height','0'); + $j('.header_top_bottom_holder').css('top','0'); + $j('.content_inner').css('margin-top','0'); + } + }); + + $j('.qode_search_close').click(function(e){ + e.preventDefault(); + $j('.qode_search_form').css('height','0'); + $j('.header_top_bottom_holder').css('top','0'); + $j('.content_inner').css('margin-top','0'); + if($scroll < 34){ $j('header.page_header').css('top',-$scroll);} + }); + + } else { + if($j('.title').hasClass('has_fixed_background')){ + var yPos = parseInt($j('.title.has_fixed_background').css('backgroundPosition').split(" ")[1]); + }else { + var yPos = 0; + } + if ($j('.qode_search_form').height() == "0") { + $j('.qode_search_form input[type="text"]').focus(); + $j('.header_top_bottom_holder').stop().animate({top:"50px"},150); + $j('.qode_search_form').stop().animate({height:"50px"},150); + $j('.content_inner').stop().animate({marginTop:"50px"},150); + if($scroll < 34){ $j('header.page_header').stop().animate({top:0},150); } + $j('.title.has_fixed_background').animate({ + 'background-position-y': (yPos + 50)+'px' + }, 150); + } else { + $j('.qode_search_form').stop().animate({height:"0"},150); + $j('.header_top_bottom_holder').stop().animate({top:"0px"},150); + $j('.content_inner').stop().animate({marginTop:"0"},150); + if($scroll < 34){ $j('header.page_header').stop().animate({top:-$scroll},150);} + $j('.title.has_fixed_background').animate({ + 'background-position-y': (yPos - 50)+'px' + }, 150); + } + + $j(window).scroll(function() { + if ($j('.qode_search_form').height() != "0" && $scroll > 50) { + $j('.qode_search_form').stop().animate({height:"0"},150); + $j('.header_top_bottom_holder').stop().animate({top:"0px"},150); + $j('.content_inner').stop().animate({marginTop:"0"},150); + $j('.title.has_fixed_background').css('backgroundPosition', 'center '+(yPos)+'px'); + } + }); + + $j('.qode_search_close').click(function(e){ + e.preventDefault(); + $j('.qode_search_form').stop().animate({height:"0"},150); + $j('.content_inner').stop().animate({marginTop:"0"},150); + $j('.header_top_bottom_holder').stop().animate({top:"0px"},150); + if($scroll < 34){ $j('header.page_header').stop().animate({top:-$scroll},150);} + $j('.title.has_fixed_background').animate({ + 'background-position-y': (yPos)+'px' + }, 150); + }); + } + }); + } + + //search type - search_slides_from_header_bottom + if($j('.search_slides_from_header_bottom').length){ + + $j('.search_slides_from_header_bottom').click(function(e){ + + e.preventDefault(); + + if($j('html').hasClass('touch')){ + if ($j('.qode_search_form_2').height() == "0") { + $j('.qode_search_form_2 input[type="text"]').onfocus = function () { + window.scrollTo(0, 0); + document.body.scrollTop = 0; + }; + $j('.qode_search_form_2 input[type="text"]').onclick = function () { + window.scrollTo(0, 0); + document.body.scrollTop = 0; + }; + $j('.qode_search_form_2').css('height','50px'); + } else { + $j('.qode_search_form_2').css('height','0'); + + } + + $j(window).scroll(function() { + if ($j('.qode_search_form_2').height() != "0" && $scroll > 50) { + $j('.qode_search_form_2').css('height','0'); + } + }); + + } else { + if($j('.qode_search_form_2').hasClass('animated')) { + $j('.qode_search_form_2').removeClass('animated'); + $j('.qode_search_form_2').css('bottom','0'); + } else { + $j('.qode_search_form input[type="text"]').focus(); + $j('.qode_search_form_2').addClass('animated'); + var search_form_height = $j('.qode_search_form_2').height(); + $j('.qode_search_form_2').css('bottom',-search_form_height); + + } + + $j('.qode_search_form_2').addClass('disabled'); + $j('.qode_search_form_2 input[type="submit"]').attr('disabled','disabled'); + if(($j('.qode_search_form_2 .qode_search_field').val() !== '') && ($j('.qode_search_form_2 .qode_search_field').val() !== ' ')) { + $j('.qode_search_form_2 input[type="submit"]').removeAttr('disabled'); + $j('.qode_search_form_2').removeClass('disabled'); + } + else { + $j('.qode_search_form_2').addClass('disabled'); + $j('.qode_search_form_2 input[type="submit"]').attr('disabled','disabled'); + } + + $j('.qode_search_form_2 .qode_search_field').keyup(function() { + if(($j(this).val() !== '') && ($j(this).val() != ' ')) { + $j('.qode_search_form_2 input[type="submit"]').removeAttr('disabled'); + $j('.qode_search_form_2').removeClass('disabled'); + } + else { + $j('.qode_search_form_2 input[type="submit"]').attr('disabled','disabled'); + $j('.qode_search_form_2').addClass('disabled'); + } + }); + + + $j('.content, footer').click(function(e){ + e.preventDefault(); + $j('.qode_search_form_2').removeClass('animated'); + $j('.qode_search_form_2').css('bottom','0'); + }); + } + }); + } + + //search type - search covers header + if($j('.search_covers_header').length){ + + $j('.search_covers_header').click(function(e){ + + e.preventDefault(); + if($j(".search_covers_only_bottom").length){ + var headerHeight = $j('.header_bottom').height(); + } + else{ + if($j(".fixed_top_header").length){ + var headerHeight = $j('.top_header').height(); + }else{ + var headerHeight = $j('.header_top_bottom_holder').height(); + } + } + + $j('.qode_search_form_3 .form_holder_outer').height(headerHeight); + + if($j(".search_covers_only_bottom").length){ + $j('.qode_search_form_3').css('bottom',0); + $j('.qode_search_form_3').css('top','auto'); + } + $j('.qode_search_form_3').stop(true).fadeIn(600,'easeOutExpo'); + $j('.qode_search_form_3 input[type="text"]').focus(); + + + $j(window).scroll(function() { + if($j(".search_covers_only_bottom").length){ + var headerHeight = $j('.header_bottom').height(); + } + else{ + if($j(".fixed_top_header").length){ + var headerHeight = $j('.top_header').height(); + }else{ + var headerHeight = $j('.header_top_bottom_holder').height(); + } + } + $j('.qode_search_form_3 .form_holder_outer').height(headerHeight); + }); + + $j('.qode_search_close, .content, footer').click(function(e){ + e.preventDefault(); + $j('.qode_search_form_3').stop(true).fadeOut(450,'easeOutExpo'); + }); + + $j('.qode_search_form_3').blur(function(e){ + $j('.qode_search_form_3').stop(true).fadeOut(450,'easeOutExpo'); + }); + }); + } + +//search type - fullscreen search + if($j('.fullscreen_search').length){ + //search type Circle Appear + if($j(".fullscreen_search_holder.from_circle").length){ + $j('.fullscreen_search').on('click',function(e){ + e.preventDefault(); + if($j('.fullscreen_search_overlay').hasClass('animate')){ + $j('.fullscreen_search_overlay').removeClass('animate'); + $j('.fullscreen_search_holder').css('opacity','0'); + $j('.fullscreen_search_close').css('opacity','0'); + $j('.fullscreen_search_close').css('visibility','hidden'); + $j('.fullscreen_search').css('opacity','1'); + $j('.fullscreen_search_holder').css('display','none'); + } else { + $j('.fullscreen_search_overlay').addClass('animate'); + $j('.fullscreen_search_holder').css('display','block'); + setTimeout(function(){ + $j('.fullscreen_search_holder').css('opacity','1'); + $j('.fullscreen_search_close').css('opacity','1'); + $j('.fullscreen_search_close').css('visibility','visible'); + $j('.fullscreen_search').css('opacity','0'); + },200); + + } + }); + $j('.fullscreen_search_close').on('click',function(e){ + e.preventDefault(); + $j('.fullscreen_search_overlay').removeClass('animate'); + $j('.fullscreen_search_holder').css('opacity','0'); + $j('.fullscreen_search_close').css('opacity','0'); + $j('.fullscreen_search_close').css('visibility','hidden'); + $j('.fullscreen_search').css('opacity','1'); + $j('.fullscreen_search_holder').css('display','none'); + + }); + } + //search type Fade Appear + if($j(".fullscreen_search_holder.fade").length){ + $j('.fullscreen_search').on('click',function(e){ + e.preventDefault(); + if($j('.fullscreen_search_holder').hasClass('animate')) { + $j('body').removeClass('fullscreen_search_opened'); + $j('.fullscreen_search_holder').removeClass('animate'); + $j('body').removeClass('search_fade_out'); + $j('body').removeClass('search_fade_in'); + + } else { + $j('body').addClass('fullscreen_search_opened'); + $j('body').removeClass('search_fade_out'); + $j('body').addClass('search_fade_in'); + $j('.fullscreen_search_holder').addClass('animate'); + + } + }); + $j('.fullscreen_search_close').on('click',function(e){ + e.preventDefault(); + $j('body').removeClass('fullscreen_search_opened'); + $j('.fullscreen_search_holder').removeClass('animate'); + $j('body').removeClass('search_fade_in'); + $j('body').addClass('search_fade_out'); + + }); + } + + //Text input focus change + $j('.fullscreen_search_holder .search_field').focus(function(){ + $j('.fullscreen_search_holder .field_holder .line').css("width","100%"); + }); + + $j('.fullscreen_search_holder .search_field').blur(function(){ + $j('.fullscreen_search_holder .field_holder .line').css("width","0"); + }); + + //search close button - setting its position vertically + $j(window).scroll(function() { + var bottom_height = $j(".page_header .header_bottom").height(); + if($j(".page_header").hasClass("sticky")){ + $j(".fullscreen_search_holder .side_menu_button").css("height",bottom_height); + $j(".fullscreen_search_holder .close_container").css("top","0"); + } else if($j(".page_header").hasClass("fixed")){ + $j(".fullscreen_search_holder .side_menu_button").css("height",bottom_height); + } else { + $j(".fullscreen_search_holder .side_menu_button").css("height",""); + $j(".fullscreen_search_holder .close_container").css("top",""); + } + }); + } + + if($j('.qode_search_submit').length) { + $j('.qode_search_submit').click(function(e) { + e.preventDefault(); + e.stopPropagation(); + + var searchForm = $j(this).parents('form').first(); + + searchForm.submit(); + }); + } + +} + +/* +** Init update Shopping Cart +*/ +function updateShoppingCart(){ + "use strict"; + + $j('body').bind('added_to_cart', add_to_cart); + function add_to_cart(event, parts, hash) { + var miniCart = $j('.shopping_cart_header'); + if ( parts['div.widget_shopping_cart_content'] ) { + var $cartContent = jQuery(parts['div.widget_shopping_cart_content']), + $itemsList = $cartContent .find('.cart_list'), + $total = $cartContent.find('.total').contents(':not(strong)').text(); + miniCart.find('.shopping_cart_dropdown_inner').html('').append($itemsList); + miniCart.find('.total span').html('').append($total); + } + } +} + + +/* +** Set content bottom margin because of the uncovering footer +*/ +function setContentBottomMargin(){ + if($j('.uncover').length){ + $j('.content').css('margin-bottom', $j('footer').height()); + } +} + +/* + ** Set footer uncover with vertical area + */ +function footerWidth(){ + "use strict"; + + if($j('.uncover').length && $j('body').hasClass('vertical_menu_enabled') && $window_width > 1000){ + $j('.uncover').width($window_width - $j('.vertical_menu_area').width()); + } else{ + $j('.uncover').css('width','100%'); + } +} + +/* +** Boxes which reveal text on hover +*/ +function initCoverBoxes(){ + if($j('.cover_boxes').length) { + $j('.cover_boxes').each(function(){ + var active_element = 0; + var data_active_element = 1; + if(typeof $j(this).data('active-element') !== 'undefined' && $j(this).data('active-element') !== false) { + data_active_element = parseFloat($j(this).data('active-element')); + active_element = data_active_element - 1; + } + + var number_of_columns = 3; + + //validate active element + active_element = data_active_element > number_of_columns ? 0 : active_element; + + $j(this).find('li').eq(active_element).addClass('act'); + var cover_boxed = $j(this); + $j(this).find('li').each(function(){ + $j(this).hover(function() { + $j(cover_boxed).find('li').removeClass('act'); + $j(this).addClass('act'); + }); + + }); + }); + } +} + +/* +** Create content menu from selected rows +*/ +function createContentMenu(){ + "use strict"; + + var content_menu = $j(".content_menu"); + content_menu.each(function(){ + if($j(this).find('ul').length === 0){ + + if($j(this).css('background-color') !== ""){ + var background_color = $j(this).css('background-color'); + } + + var content_menu_ul = $j(""); + content_menu_ul.appendTo($j(this)); + + var sections = $j(this).siblings('.in_content_menu'); + + if(sections.length){ + sections.each(function(){ + var section_href = $j(this).data("q_id"); + var section_title = $j(this).data('q_title'); + var section_icon = $j(this).data('q_icon'); + + var li = $j("
  • "); + var icon = $j("", {"class": 'fa '+section_icon}); + var link = $j("", {"href": section_href, "html": "" + section_title + ""}); + var arrow; + if(background_color !== ""){ + arrow = $j("
    ", {"class": 'arrow', "style": 'border-color: '+background_color+' transparent transparent transparent'}); + } else { + arrow = $j("
    ", {"class": 'arrow'}); + } + icon.prependTo(link); + link.appendTo(li); + arrow.appendTo(li); + li.appendTo(content_menu_ul); + + }); + } + } + }); +} + +/* +** Create content menu (select menu for responsiveness)from selected rows +*/ +function createSelectContentMenu(){ + "use strict"; + + var content_menu = $j(".content_menu"); + content_menu.each(function(){ + + var $this = $j(this); + + var $menu_select = $j("
      "); + $menu_select.appendTo($j(this).find('.nav_select_menu')); + + + $j(this).find("ul.menu li a").each(function(){ + + var menu_url = $j(this).attr("href"); + var menu_text = $j(this).text(); + var menu_icon = $j(this).find('i').clone(); + + if ($j(this).parents("li").length === 2) { menu_text = "   " + menu_text; } + if ($j(this).parents("li").length === 3) { menu_text = "      " + menu_text; } + if ($j(this).parents("li").length > 3) { menu_text = "         " + menu_text; } + + var li = $j("
    • "); + var link = $j("", {"href": menu_url, "html": menu_text}); + menu_icon.prependTo(link); + link.appendTo(li); + li.appendTo($menu_select); + }); + + + $this.find(".nav_select_button").on('click', function() { + if ($this.find('.nav_select_menu ul').is(":visible")){ + $this.find('.nav_select_menu ul').slideUp(); + } else { + $this.find('.nav_select_menu ul').slideDown(); + } + return false; + }); + + $this.find(".nav_select_menu ul li a").on('click',function () { + $this.find('.nav_select_menu ul').slideUp(); + var $link = $j(this); + + var $target = $link.attr("href"); + var targetOffset = $j("div.wpb_row[data-q_id='" + $target + "'],section.parallax_section_holder[data-q_id='" + $target + "']").offset().top; + + $j('html,body').stop().animate({scrollTop: targetOffset }, 500, 'swing', function(){ + $j('nav.content_menu ul li').removeClass('active'); + $link.parent().addClass('active'); + }); + + return false; + }); + }); +} + +/* +** Calculate content menu position and fix it when needed +*/ +function contentMenuPosition(){ + "use strict"; + + if($j('nav.content_menu').length){ + + if(content_menu_position > sticky_amount){ + var x = min_header_height_sticky; + }else{ + var x = 0; + } + + if(content_menu_position - x - content_menu_top_add - $scroll <= 0 && ($j('header').hasClass('stick') || $j('header').hasClass('stick_with_left_right_menu'))){ + + if(content_menu_position < sticky_amount){ + if($scroll > sticky_amount){ + $j('nav.content_menu').css({'position': 'fixed', 'top': min_header_height_sticky + content_menu_top_add}).addClass('fixed'); + + }else{ + $j('nav.content_menu').css({'position': 'fixed', 'top': 0, transition:'none'}).addClass('fixed'); + } + }else{ + $j('nav.content_menu').css({'position': 'fixed', 'top': min_header_height_sticky + content_menu_top_add}).addClass('fixed'); + } + $j('header.sticky').addClass('no_shadow'); + $j('.content > .content_inner > .container > .container_inner').css('margin-top',content_line_height); + $j('.content > .content_inner > .full_width').css('margin-top',content_line_height); + + } else if(content_menu_position - content_menu_top - content_menu_top_add - $scroll <= 0 && !($j('header').hasClass('stick'))) { + $j('nav.content_menu').css({'position': 'fixed', 'top': content_menu_top + content_menu_top_add}).addClass('fixed'); + $j('.content > .content_inner > .container > .container_inner').css('margin-top',content_line_height); + $j('.content > .content_inner > .full_width').css('margin-top',content_line_height); + } else { + $j('nav.content_menu').css({'position': 'relative', 'top': '0px'}).removeClass('fixed'); + $j('header.sticky').removeClass('no_shadow'); + $j('.content > .content_inner > .container > .container_inner').css('margin-top','0px'); + $j('.content > .content_inner > .full_width').css('margin-top','0px'); + } + + $j('.content .in_content_menu').waypoint( function(direction) { + var $active = $j(this); + var id = $active.data("q_id"); + + $j("nav.content_menu.fixed li a").each(function(){ + var i = $j(this).attr("href"); + if(i === id){ + $j(this).parent().addClass('active'); + }else{ + $j(this).parent().removeClass('active'); + } + }); + }, { offset: '150' }); + } +} + +/* +** Check first and last content menu included rows for active state in content menu +*/ +function contentMenuCheckLastSection(){ + "use strict"; + + if($j('nav.content_menu').length){ + + if($j('.content .in_content_menu').length){ + var last_from_top = $j('.content .in_content_menu:last').offset().top + $j('.content .in_content_menu:last').height(); + var first_from_top = $j('.content .in_content_menu:first').offset().top - content_menu_top - content_menu_top_add - 100; //60 is height of content menu + if(last_from_top < $scroll){ + $j("nav.content_menu.fixed li").removeClass('active'); + + } + if(first_from_top > $scroll){ + $j('nav.content_menu li:first, nav.content_menu ul.menu li:first').removeClass('active'); + + } + } + + } +} + +/* +** Scroll to section when item in content menu is clicked +*/ +function contentMenuScrollTo(){ + "use strict"; + + if($j('nav.content_menu').length){ + + $j("nav.content_menu ul.menu li a").on('click', function(e){ + e.preventDefault(); + var $this = $j(this); + + if($j(this).parent().hasClass('active')){ + return false; + } + + var $target = $this.attr("href"); + var targetOffset = $j("div.wpb_row[data-q_id='" + $target + "'],section.parallax_section_holder[data-q_id='" + $target + "']").offset().top - content_line_height - content_menu_top - content_menu_top_add; + $j('html,body').stop().animate({scrollTop: targetOffset }, 500, 'swing', function(){ + $j('nav.content_menu ul li').removeClass('active'); + $this.parent().addClass('active'); + }); + + return false; + }); + + } +} + +function initButtonHover() { + if($j('.qbutton').length) { + $j('.qbutton').each(function() { + + //hover background color + if(typeof $j(this).data('hover-background-color') !== 'undefined' && $j(this).data('hover-background-color') !== false) { + var hover_background_color = $j(this).data('hover-background-color'); + var initial_background_color = $j(this).css('background-color'); + $j(this).hover( + function() { + $j(this).css('background-color', hover_background_color); + }, + function() { + $j(this).css('background-color', initial_background_color); + }); + } + + //hover border color + if(typeof $j(this).data('hover-border-color') !== 'undefined' && $j(this).data('hover-border-color') !== false) { + var hover_border_color = $j(this).data('hover-border-color'); + var initial_border_color = $j(this).css('border-top-color'); + $j(this).hover( + function() { + $j(this).css('border-color', hover_border_color); + }, + function() { + $j(this).css('border-color', initial_border_color); + }); + } + + //hover color + if(typeof $j(this).data('hover-color') !== 'undefined' && $j(this).data('hover-color') !== false) { + var hover_color = $j(this).data('hover-color'); + var initial_color = $j(this).css('color'); + $j(this).hover( + function() { + $j(this).css('color', hover_color); + }, + function() { + $j(this).css('color', initial_color); + }); + } + }); + } +} + +function initSocialIconHover() { + if($j('.q_social_icon_holder').length) { + $j('.q_social_icon_holder').each(function() { + + //hover background color + if(typeof $j(this).data('hover-background-color') !== 'undefined' && $j(this).data('hover-background-color') !== false) { + var hover_background_color = $j(this).data('hover-background-color'); + var initial_background_color = $j(this).find('.fa-stack').css('background-color'); + $j(this).find('.fa-stack').hover( + function() { + + $j(this).css('background-color', hover_background_color); + }, + function() { + $j(this).css('background-color', initial_background_color); + }); + } + + //hover border color + if(typeof $j(this).data('hover-border-color') !== 'undefined' && $j(this).data('hover-border-color') !== false) { + var hover_border_color = $j(this).data('hover-border-color'); + var initial_border_color = $j(this).find('.fa-stack').css('border-top-color'); + $j(this).find('.fa-stack').hover( + function() { + $j(this).css('border-color', hover_border_color); + }, + function() { + $j(this).css('border-color', initial_border_color); + } + ); + } + + //hover color + if(typeof $j(this).data('hover-color') !== 'undefined' && $j(this).data('hover-color') !== false) { + var initial_color; + var initial_style; + var hover_color = $j(this).data('hover-color'); + + if($j(this).find('.fa-stack i, .fa-stack span').length) { + initial_color = $j(this).find('.fa-stack i, .fa-stack span').css('color'); + initial_style = $j(this).find('.fa-stack i, .fa-stack span').attr('style'); + } else if($j(this).find('.simple_social').length) { + initial_color = $j(this).find('.simple_social').css('color'); + initial_style = $j(this).find('.simple_social').attr('style'); + } + + if($j(this).find('.fa-stack').length) { + $j(this).find('.fa-stack').hover( + function() { + $j(this).find('i, span').attr('style', function(i, s) { return initial_style + 'color: '+ hover_color + '!important;'}); + }, + function() { + $j(this).find('i, span').attr('style', function(i, s) { return initial_style + 'color: ' + initial_color + '!important;' }); + }); + } else if($j(this).find('.simple_social').length) { + $j(this).find('.simple_social').hover( + function(){ + $j(this).attr('style', function(i, s) { return initial_style + 'color: '+ hover_color + '!important;' }); + }, + function(){ + $j(this).attr('style', function(i, s) { return initial_style + 'color: '+ initial_color + '!important;' }); + }); + } + + } + }); + } +} + +function initTabsActiveBorder() { + if($j('.q_tabs.vertical, .q_tabs.boxed').length) { + $j('.q_tabs.vertical, .q_tabs.boxed').each(function(){ + var parentBgColor = getParentBackgroundColor($j(this)); + + var activeElement = $j(this).find('li.active a'); + if($j(this).hasClass('boxed')) { + activeElement.css('border-bottom-color', parentBgColor); + } + + if($j(this).hasClass('left')) { + activeElement.css('border-right-color', parentBgColor); + } + + if($j(this).hasClass('right')) { + activeElement.css('border-left-color', parentBgColor); + } + }); + } +} + +function getParentBackgroundColor(element) { + return element.parents().filter(function(){ + var color = $j(this).css('background-color'); + return color != 'transparent' && color != 'rgba(0, 0, 0, 0)'; + }).eq(0).css('background-color') +} + +function setActiveTabBorder() { + if($j('.q_tabs li.active').length) { + $j(this).click(function() { + initTabsActiveBorder(); + }); + } +} + +/* + ** Popup menu initialization + */ + +function initPopupMenu(){ + "use strict"; + + if($j('a.popup_menu').length){ + //var body_top; + + //set height of popup holder and initialize nicescroll + $j(".popup_menu_holder_outer").height($window_height).niceScroll({ + scrollspeed: 30, + mousescrollstep: 20, + cursorwidth: 0, + cursorborder: 0, + cursorborderradius: 0, + cursorcolor: "transparent", + autohidemode: false, + horizrailenabled: false + }); //200 is top and bottom padding of holder + + //set height of popup holder on resize + $j(window).resize(function() {$j(".popup_menu_holder_outer").height($window_height)}); + + // Open popup menu + $j('a.popup_menu').on('click',function(e){ + e.preventDefault(); + + if(!$j(this).hasClass('opened')){ + $j(this).addClass('opened'); + $j('body').addClass('popup_menu_opened'); + setTimeout(function(){ + if(!$j('body').hasClass('page-template-full_screen-php')){ + $j('body').css('overflow','hidden'); + } + },400); + }else{ + $j(this).removeClass('opened'); + $j('body').removeClass('popup_menu_opened'); + + setTimeout(function(){ + if(!$j('body').hasClass('page-template-full_screen-php')){ + $j('body').css('overflow','visible'); + } + $j("nav.popup_menu ul.sub_menu").slideUp(200, function(){ + $j('nav.popup_menu').getNiceScroll().resize(); + }); + },400); + + } + }); + + //logic for open sub menus in popup menu + $j(".popup_menu > ul > li.has_sub > a, .popup_menu > ul > li.has_sub > h6").on('tap click', function (e) { + e.preventDefault(); + + if ($j(this).closest('li.has_sub').find("> ul.sub_menu").is(":visible")){ + $j(this).closest('li.has_sub').find("> ul.sub_menu").slideUp(200, function(){ + $j('.popup_menu_holder_outer').getNiceScroll().resize(); + }); + $j(this).closest('li.has_sub').removeClass('open_sub'); + } else { + $j(this).closest('li.has_sub').addClass('open_sub'); + $j(this).closest('li.has_sub').find("> ul.sub_menu").slideDown(200, function(){ + $j('.popup_menu_holder_outer').getNiceScroll().resize(); + }); + } + + return false; + }); + +// $j(".popup_menu > ul > li.has_sub > ul.sub_menu > li.has_sub > a > span.popup_arrow, .popup_menu > ul > li.has_sub > ul.sub_menu > li.has_sub > h6").click(function () { +// if ($j(this).parent().parent().find("ul.sub_menu").is(":visible")){ +// $j(this).parent().parent().find("ul.sub_menu").slideUp(200); +// $j(this).parent().parent().removeClass('open_sub'); +// } else { +// $j(this).parent().parent().addClass('open_sub'); +// $j(this).parent().parent().find("ul.sub_menu").slideDown(200); +// } +// }); + + //if link has no submenu and if it's not dead, than open that link + $j(".popup_menu ul li:not(.has_sub) a").click(function () { + if(($j(this).attr('href') !== "http://#") && ($j(this).attr('href') !== "#")){ + $j('a.popup_menu').removeClass('opened'); + $j('body').removeClass('popup_menu_opened').css('overflow','visible'); + $j("nav.popup_menu ul.sub_menu").slideUp(200, function(){ + $j('nav.popup_menu').getNiceScroll().resize(); + }); + }else{ + return false; + } + }); + } +} + +function initFullScreenTemplate(){ + "use strict"; + + if($j('.full_screen_holder').length && $window_width > 600){ + + // used for header style on changing sections, in checkFullScreenSectionsForHeaderStyle functions - START // + var default_header_style = ''; + if ($j('header.page_header').hasClass('light')) { + default_header_style = 'light'; + } else if ($j('header.page_header').hasClass('dark')) { + default_header_style = 'dark'; + } else { + default_header_style = header_style_admin; + } + // used for header style on changing sections, in checkFullScreenSectionsForHeaderStyle functions - END // + + $j('.full_screen_preloader').css('height', ($window_height)); + + $j('#up_fs_button').on('click', function() { + $j.fn.fullpage.moveSectionUp(); + return false; + }); + + $j('#down_fs_button').on('click', function() { + $j.fn.fullpage.moveSectionDown(); + return false; + }); + + var section_number = $j('.full_screen_inner > .full_screen_section').length; + $j('.full_screen_inner').fullpage({ + sectionSelector: '.full_screen_section', + scrollOverflow: true, + afterLoad: function(anchorLink, index){ + checkActiveArrowsOnFullScrrenTemplate(section_number, index); + checkFullScreenSectionsForHeaderStyle(index, default_header_style); + }, + afterRender: function(){ + checkActiveArrowsOnFullScrrenTemplate(section_number, 1); + checkFullScreenSectionsForHeaderStyle(1, default_header_style); + if(section_number !== 1){ + $j('.full_screen_holder').find('.full_screen_navigation_holder').css('visibility','visible'); + } + $j('.full_screen_holder').find('.full_screen_inner').css('visibility','visible'); + $j('.full_screen_preloader').hide(); + if($j('.full_screen_holder video.full_screen_sections_video').length){ + $j('.full_screen_holder video.full_screen_sections_video').each(function(){ + $j(this).get(0).play(); + }); + } + } + }); + } +} + +function checkActiveArrowsOnFullScrrenTemplate(section_number, index){ + "use strict"; + + if(index === 1){ + $j('.full_screen_navigation_holder #up_fs_button').hide(); + if(index != section_number){ + $j('.full_screen_navigation_holder #down_fs_button').show(); + } + }else if(index === section_number){ + if(section_number === 2){ + $j('.full_screen_navigation_holder #up_fs_button').show(); + } + $j('.full_screen_navigation_holder #down_fs_button').hide(); + }else{ + $j('.full_screen_navigation_holder #up_fs_button').show(); + $j('.full_screen_navigation_holder #down_fs_button').show(); + } +} + +function checkFullScreenSectionsForHeaderStyle(index, default_header_style){ + "use strict"; + + if($j('[data-q_header_style]').length > 0 && $j('header').hasClass('header_style_on_scroll')) { + if ($j($j('.full_screen_holder .full_screen_inner .full_screen_section')[index-1]).data("q_header_style") !== undefined) { + var header_style = $j($j('.full_screen_holder .full_screen_inner .full_screen_section')[index-1]).data("q_header_style"); + $j('header').removeClass('dark light').addClass(header_style); + } else { + + $j('header').removeClass('dark light').addClass(default_header_style); + } + } +} + +/* + * Check header style on scroll + */ + +function checkHeaderStyleOnScroll(){ + "use strict"; + + if($j('[data-q_header_style]').length > 0 && $j('header').hasClass('header_style_on_scroll')){ + + //var offset = $j('header.page_header').height(); + var default_header_style = ''; + if($j('header.page_header').hasClass('light')){ + default_header_style = 'light'; + }else if($j('header.page_header').hasClass('dark')){ + default_header_style = 'dark'; + }else{ + default_header_style = header_style_admin; + } + + var paspartu_top_add = $j('body').hasClass('paspartu_on_top_fixed') ? Math.round($window_width*paspartu_width) : 0; + var paspartu_bottom_add = $j('body').hasClass('paspartu_on_bottom_fixed') ? Math.round($window_width*paspartu_width) : 0; + + $j('.full_width_inner > .wpb_row.section, .full_width_inner > .parallax_section_holder, .container_inner > .wpb_row.section, .container_inner > .parallax_section_holder, .portfolio_single > .wpb_row.section').waypoint( function(direction) { + if(direction === 'down') { + if ($j(this).data("q_header_style") !== undefined) { + var header_style = $j(this).data("q_header_style"); + $j('header').removeClass('dark light').addClass(header_style); + } else { + $j('header').removeClass('dark light').addClass(default_header_style); + } + } + + }, { offset: 0 + paspartu_top_add}); + + //'title' class is added in selector because default header style is not set when there is title on the page and page is scrolled back to the top + $j('.title, .full_width_inner > .wpb_row.section, .full_width_inner > .parallax_section_holder, .container_inner > .wpb_row.section, .container_inner > .parallax_section_holder, .portfolio_single > .wpb_row.section, .q_slider').waypoint( function(direction) { + + if(direction === 'up') { + if ($j(this).data("q_header_style") !== undefined) { + var header_style = $j(this).data("q_header_style"); + $j('header').removeClass('dark light').addClass(header_style); + } else { + $j('header').removeClass('dark light').addClass(default_header_style); + } + } + + }, { offset: function(){ + return -$j(this).outerHeight() + paspartu_bottom_add; + } }); + } +} + +/* + ** Image Gallery Slider with no space initialization + */ +function initImageGallerySliderNoSpace(){ + if($j('.qode_image_gallery_no_space').length){ + $j('.qode_image_gallery_no_space').each(function(){ + $j(this).animate({'opacity': 1},1000); + $j(this).find('.qode_image_gallery_holder').lemmonSlider({infinite: true}); + }); + + //disable click on non active image + $j('.qode_image_gallery_no_space').on('click', 'li:not(.active) a', function() { + return false; + }); + } +} + +/* + ** Vertical Split Slider + */ + +function initVerticalSplitSlider(){ + "use strict"; + if($j('html').hasClass('vertical_split_screen_initalized')){ + $j('html').removeClass('vertical_split_screen_initalized'); + $j.fn.multiscroll.destroy(); + } + if($j('.vertical_split_slider').length) { + $j('.vertical_split_slider').height($window_height).animate({opacity:1},300); + $j('.vertical_split_slider').multiscroll({ + scrollingSpeed: 500, + navigation: true, + afterRender: function(){ + $j('html').addClass('vertical_split_screen_initalized'); + initButtonHover(); // this function need to be initialized after initVerticalSplitSlider + if($j('div.wpcf7 > form').length){$j('div.wpcf7 > form').wpcf7InitForm();} // this function need to be initialized after initVerticalSplitSlider in order to initialize + initCountdown(); + + if ($j('body').hasClass('vss_responsive_adv')){ + //prepare html for smaller screens - start // + var vertical_split_slider_responsive = $j("
      "); + $j(".vertical_split_slider").after(vertical_split_slider_responsive); + var left_side = $j('.vertical_split_slider .ms-left > div'); + + var right_side = $j('.vertical_split_slider .ms-right > div'); + for(var i = 0; i < left_side.length; i++){ + vertical_split_slider_responsive.append($j(left_side[i]).clone(true)); + vertical_split_slider_responsive.append($j(right_side[left_side.length-1-i]).clone(true)); + } + } + + } + }); + + if ($j('body').hasClass('vss_responsive_adv')){ + if($window_width < 768){ + $j.fn.multiscroll.destroy(); + $j('html,body').css('height', 'auto').css('overflow', 'auto'); + }else{ + $j.fn.multiscroll.build(); + $j('html,body').css('height', '100%').css('overflow', 'hidden'); + } + + $j(window).resize(function() { + if($window_width < 768){ + $j.fn.multiscroll.destroy(); + $j('html,body').css('height', 'auto').css('overflow', 'auto'); + }else{ + $j.fn.multiscroll.build(); + $j('html,body').css('height', '100%').css('overflow', 'hidden'); + } + }); + } + + }else{ + if(!$j('.full_screen_holder').length) { //because this is not necessary on pages if there are full screen sections + $j('html,body').css('height', 'auto').css('overflow', 'auto'); + } + } +} + +/* +** Show Google Map +*/ +function showGoogleMap(){ + "use strict"; + + if($j('.qode_google_map').length){ + $j('.qode_google_map').each(function(){ + + var custom_map_style; + if(typeof $j(this).data('custom-map-style') !== 'undefined') { + custom_map_style = $j(this).data('custom-map-style'); + } + + var color_overlay; + if(typeof $j(this).data('color-overlay') !== 'undefined' && $j(this).data('color-overlay') !== false) { + color_overlay = $j(this).data('color-overlay'); + } + + var saturation; + if(typeof $j(this).data('saturation') !== 'undefined' && $j(this).data('saturation') !== false) { + saturation = $j(this).data('saturation'); + } + + var lightness; + if(typeof $j(this).data('lightness') !== 'undefined' && $j(this).data('lightness') !== false) { + lightness = $j(this).data('lightness'); + } + + var zoom; + if(typeof $j(this).data('zoom') !== 'undefined' && $j(this).data('zoom') !== false) { + zoom = $j(this).data('zoom'); + } + + var pin; + if(typeof $j(this).data('pin') !== 'undefined' && $j(this).data('pin') !== false) { + pin = $j(this).data('pin'); + } + + var map_height; + if(typeof $j(this).data('map-height') !== 'undefined' && $j(this).data('map-height') !== false) { + map_height = $j(this).data('map-height'); + } + + var unique_id; + if(typeof $j(this).data('unique-id') !== 'undefined' && $j(this).data('unique-id') !== false) { + unique_id = $j(this).data('unique-id'); + } + + var google_maps_scroll_wheel; + if(typeof $j(this).data('google-maps-scroll-wheel') !== 'undefined') { + google_maps_scroll_wheel = $j(this).data('google-maps-scroll-wheel'); + } + var addresses; + if(typeof $j(this).data('addresses') !== 'undefined' && $j(this).data('addresses') !== false) { + addresses = $j(this).data('addresses'); + } + + + var map = "map_"+ unique_id; + var geocoder = "geocoder_"+ unique_id; + var holderId = "map_canvas_"+ unique_id; + + initializeGoogleMap(custom_map_style, color_overlay, saturation, lightness, google_maps_scroll_wheel, zoom, holderId, map_height, pin, map, geocoder, addresses) + }); + } + +} +/* + ** Init Google Map + */ +function initializeGoogleMap(custom_map_style, color, saturation, lightness, wheel, zoom, holderId, height, pin, map, geocoder, data){ + "use strict"; + + var mapStyles = [ + { + stylers: [ + {hue: color }, + {saturation: saturation}, + {lightness: lightness}, + {gamma: 1} + ] + } + ]; + + var google_map_type_id; + + if(custom_map_style){ + google_map_type_id = 'qode_style' + } else { + google_map_type_id = google.maps.MapTypeId.ROADMAP + } + + var qodeMapType = new google.maps.StyledMapType(mapStyles, + {name: "Qode Google Map"}); + + geocoder = new google.maps.Geocoder(); + var latlng = new google.maps.LatLng(-34.397, 150.644); + + var myOptions = { + + zoom: zoom, + scrollwheel: wheel, + center: latlng, + zoomControl: true, + zoomControlOptions: { + style: google.maps.ZoomControlStyle.SMALL, + position: google.maps.ControlPosition.RIGHT_CENTER + }, + scaleControl: false, + scaleControlOptions: { + position: google.maps.ControlPosition.LEFT_CENTER + }, + streetViewControl: false, + streetViewControlOptions: { + position: google.maps.ControlPosition.LEFT_CENTER + }, + panControl: false, + panControlOptions: { + position: google.maps.ControlPosition.LEFT_CENTER + }, + mapTypeControl: false, + mapTypeControlOptions: { + mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'qode_style'], + style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR, + position: google.maps.ControlPosition.LEFT_CENTER + }, + mapTypeId: google_map_type_id + }; + map = new google.maps.Map(document.getElementById(holderId), myOptions); + map.mapTypes.set('qode_style', qodeMapType); + + var index; + + for (index = 0; index < data.length; ++index) { + initializeGoogleAddress(data[index], pin, map, geocoder); + } + + var holder_element = document.getElementById(holderId); + holder_element.style.height = height + "px"; + + + + +} +/* + ** Init Google Map Addresses + */ +function initializeGoogleAddress(data, pin, map, geocoder){ + "use strict"; + if (data === '') + return; + var contentString = '
      '+ + '
      '+ + '
      '+ + '
      '+ + '

      '+data+'

      '+ + '
      '+ + '
      '; + var infowindow = new google.maps.InfoWindow({ + content: contentString + }); + geocoder.geocode( { 'address': data}, function(results, status) { + if (status === google.maps.GeocoderStatus.OK) { + map.setCenter(results[0].geometry.location); + var marker = new google.maps.Marker({ + map: map, + position: results[0].geometry.location, + icon: pin, + title: data['store_title'] + }); + google.maps.event.addListener(marker, 'click', function() { + infowindow.open(map,marker); + }); + + google.maps.event.addDomListener(window, 'resize', function() { + map.setCenter(results[0].geometry.location); + }); + } + }); +}; + + +function checkSVG(element) { + "use strict"; + + var el = element.find('.active .qode_slide-svg-holder'); + var drawing_enabled = el.data('svg-drawing'); + + if (drawing_enabled === 'yes') { + drawSVG(el); + } +} + +/** + * Function for drawing slider svgs. Based on Codrops article 'SVG Drawing Animation' + */ +function drawSVG(svg){ + "use strict"; + var svgs = Array.prototype.slice.call( svg.find('svg') ), + svgArr = [], + resizeTimeout; + // the svgs already shown... + svgs.forEach( function( el, i ) { + var svg = new SVGEl( el ); + svgArr[i] = svg; + setTimeout(function( el ) { + return function() { + svg.render(); + }; + }( el ), 0 );//0ms pause before drawing + } ); +} +var docElem = window.document.documentElement; +window.requestAnimFrame = function(){ + return ( + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(/* function */ callback){ + window.setTimeout(callback, 1000 / 60); + } + ); +}(); +window.cancelAnimFrame = function(){ + return ( + window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.oCancelAnimationFrame || + window.msCancelAnimationFrame || + function(id){ + window.clearTimeout(id); + } + ); +}(); +function SVGEl( el ) { + this.el = el; + var frameRate = $j(this.el).closest('.qode_slide-svg-holder').data('svg-frames'); + this.image = this.el.previousElementSibling; + this.current_frame = 0; + this.total_frames = frameRate;//number of frames defines speed of drawing + this.path = []; + this.length = []; + this.handle = 0; + this.init(); +} +SVGEl.prototype.init = function() { + var self = this; + [].slice.call( this.el.querySelectorAll( 'path' ) ).forEach( function( path, i ) { + self.path[i] = path; + var l = self.path[i].getTotalLength(); + self.length[i] = l; + self.path[i].style.strokeDasharray = l + ' ' + l; + self.path[i].style.strokeDashoffset = l; + } ); +}; +SVGEl.prototype.render = function() { + if( this.rendered ) return; + this.rendered = true; + this.draw(); +}; +SVGEl.prototype.draw = function() { + var self = this, + progress = this.current_frame/this.total_frames; + if (progress > 1) { + window.cancelAnimFrame(this.handle); + } else { + this.current_frame++; + for(var j=0, len = this.path.length; j 0) { + var skrollr_title = skrollr.init({ + edgeStrategy: 'set', + smoothScrolling: false, + forceHeight: false + }); + skrollr_title.refresh(); + + } +}; + +function initQodeElementAnimationSkrollr() { + "use strict"; + if($j('.no-touch .carousel').length === 0) { + + var elementItemAnimation = $j('.no-touch .q_elements_holder > .q_elements_item'); + elementItemAnimation.each(function(){ + + if((typeof($j(this).data('animation')) !== 'undefined' || typeof($j('.title_outer').data('animation')) !== 'undefined') && $j(this).data('animation') === 'yes') { + var skr = skrollr.init(); + skr.refresh(); + return false; + } + + }); + } + +}; + +function initIconShortcodeHover() { + "use strict"; + + if($j('.qode_icon_shortcode').length) { + + $j('.qode_icon_shortcode').each(function() { + //check if icon type is circle of square + if(typeof $j(this).data('type') !== 'undefined' && ['circle', 'square'].indexOf($j(this).data('type')) != -1) { + + if(typeof $j(this).data('hover-bg-color') !== 'undefined') { + if($j(this).data('type') == 'circle') { + var elementToHover = $j(this).find('i').first(); + var hoverBgColor = $j(this).data('hover-bg-color'); + var initialStyle = elementToHover.attr('style'); + + $j(this).hover(function() { + elementToHover.attr('style', initialStyle + 'color: ' + hoverBgColor + '!important'); + }, function() { + elementToHover.attr('style', initialStyle); + }); + } else { + var hoverBgColor = $j(this).data('hover-bg-color'); + var initialBgColor = $j(this).css('background-color'); + + $j(this).hover(function() { + $j(this).css('background-color', hoverBgColor); + }, function() { + $j(this).css('background-color', initialBgColor); + }); + } + } + } + + if(typeof $j(this).data('hover-icon-color') !== 'undefined') { + var hoverColor = $j(this).data('hover-icon-color'); + var initialColor = $j(this).find('.qode_icon_element ').css('color'); + + $j(this).hover(function() { + $j(this).find('.qode_icon_element ').css('color', hoverColor); + }, function() { + $j(this).find('.qode_icon_element ').css('color', initialColor); + }); + } + }); + } +} + +function initIconWithTextHover() { + "use strict"; + + if($j('.qode_iwt_icon_holder').length) { + $j('.qode_iwt_icon_holder').each(function() { + if(typeof $j(this).data('icon-hover-bg-color') !== 'undefined') { + var hoverBgColor = $j(this).data('icon-hover-bg-color'); + var initialBgColor = $j(this).css('background-color'); + + $j(this).hover(function() { + $j(this).css('background-color', hoverBgColor); + }, function() { + $j(this).css('background-color', initialBgColor); + }); + } + + if(typeof $j(this).data('icon-hover-color') !== 'undefined') { + var elementToChange = $j(this).find('.qode_iwt_icon_element'); + var hoverColor = $j(this).data('icon-hover-color'); + var initialColor = elementToChange.css('color'); + + $j(this).hover(function() { + elementToChange.css('color', hoverColor); + }, function() { + elementToChange.css('color', initialColor); + }); + } + }); + } +} + +function initLoadNextPostOnBottom(){ + "use strict"; + + if($j('.blog_vertical_loop').length) { + var header_addition; + var normal_header_addition; + var paspartu_add = $j('body').hasClass('paspartu_enabled') ? Math.round($window_width*paspartu_width) : 0; + + if($j('header.page_header').hasClass('transparent')) { + normal_header_addition = 0; + }else{ + normal_header_addition = header_height; + } + + var click = true; + + var $container = $j('.blog_vertical_loop .blog_holder'); + $j(document).on('click','.blog_vertical_loop_button a',function(e){ + e.preventDefault(); + if(click){ + click = false; + var $this = $j(this); + + var link = $this.attr('href'); + var $content = '.blog_vertical_loop .blog_holder'; + var $anchor = '.blog_vertical_loop_button_holder a'; + var $next_href = $j($anchor).attr('href'); + + //check for mobile header + if($window_width < 1000){ + header_addition = $j('header.page_header').height(); + }else{ + header_addition = normal_header_addition; + } + + var scrollTop = $j(window).scrollTop(), + elementOffset = $this.closest('article').offset().top, + distance = (elementOffset - scrollTop) - header_addition - paspartu_add; + + $container.find('article:eq(1)').addClass('fade_out'); + $this.closest('article').addClass('move_up').removeClass('next_post').css('transform', 'translateY(-' + distance + 'px)'); + setTimeout(function () { + $j(window).scrollTop(0); + $container.find('article:eq(0)').remove(); + $container.find('article:eq(0)').addClass('previous_post'); + $this.closest('article').removeAttr('style').removeClass('move_up'); + }, 450); + + + $j.get(link + '', function (data) { + var $new_content = $j(data).find('article').addClass('next_post'); + $next_href = $j($anchor, data).attr('href'); + $container.append($j($new_content)); + click = true; + }); + } + else{ + return false; + } + }); + + $j(document).on('click','.blog_vertical_loop_back_button a',function(e){ + e.preventDefault(); + if(click){ + click = false; + var $this = $j(this); + + var link = $this.attr('href'); + var $content = '.blog_vertical_loop .blog_holder'; + var $anchor = '.blog_vertical_loop_button_holder.prev_post a'; + var $prev_href = $j($anchor).attr('href'); + + $container.find('article:eq(0)').removeClass('fade_out').addClass('fade_in'); + $this.closest('article').addClass('move_up').css('transform', 'translateY(' + $window_height + 'px)'); + setTimeout(function () { + $container.find('article:last-child').remove(); + $container.find('article:eq(0)').removeClass('previous_post fade_in'); + $this.closest('article').addClass('next_post').removeAttr('style').removeClass('move_up'); + + $j.get(link + '', function (data) { + var $new_content = $j(data).find('article').removeClass('next_post').addClass('previous_post'); //by default, posts have next_post class + $prev_href = $j($anchor, data).attr('href'); + $container.prepend($j($new_content)); + click = true; + }); + + }, 450); + + }else{ + return false; + } + + }); + + //load previous post on page load + $j.get($j('.blog_vertical_loop_button_holder .last_page a').attr('href') + '', function (data) { + var $new_content = $j(data).find('article').removeClass('next_post').addClass('previous_post'); //by default, posts have next_post class + $container.prepend($j($new_content)); + }); + //load next post on page load + $j.get($j('.blog_vertical_loop_button a').attr('href') + '', function (data) { + var $new_content = $j(data).find('article').addClass('next_post'); + $container.append($j($new_content)); + }); + } +} + +/* + Parallax Layers plugin + */ + +(function ( $ ) { + "use strict"; + + $.fn.extend({ + + mouseParallax: function(options) { + + var defaults = { moveFactor: 1.5, targetContainer: this }; + + var options = $.extend(defaults, options); + + return this.each(function() { + var o = options; + var layer_elements = $(o.targetContainer).find('.image, .paralax_layers_content_holder'); + + layer_elements.each(function(i){ + $(this).css('z-index',i); + }); + + var mouseXStart; + var mouseYStart; + + mouseXStart = $(o.targetContainer).offset().left; + mouseYStart = $(o.targetContainer).offset().top; + + $(o.targetContainer).on('mouseenter',function(e){ + mouseXStart = e.pageX - $(this).offset().left; + mouseYStart = e.pageY - $(this).offset().top; + }); + + $(o.targetContainer).on('mousemove', function(e){ + + var mouseX0 = $(this).offset().left + mouseXStart; + var mouseY0 = $(this).offset().top + mouseYStart; + + var mouseX = e.pageX - mouseX0; + var mouseY = e.pageY - mouseY0; + + layer_elements.each(function(i){ + $(this).css({ + marginLeft : -mouseX / 100 * o.moveFactor*(i+1), + marginTop : -mouseY / 100 * o.moveFactor*(i+1) + },100); + }); + }); + var config = { + interval: 0, + over: function(){}, + timeout: 500, + out: function(){ + layer_elements.each(function(i){ + $(this).stop().animate({ + marginLeft: 0, + marginTop: 0 + },300); + }); + } + }; + + $(o.targetContainer).hoverIntent(config); + + }); + } + + + }); +} (jQuery) ); + +/** + * Initialize parallax layers function + */ + +function setParallaxLayersHeight($this, $def_height){ + "use strict"; + + var parallax_layers_height = $def_height; + var responsive_breakpoint_set = [1600,1300,1000,768,567,320]; + if($window_width > responsive_breakpoint_set[0]){ + parallax_layers_height = $def_height; + }else if($window_width > responsive_breakpoint_set[1]){ + parallax_layers_height = $def_height * 0.75; + }else if($window_width > responsive_breakpoint_set[2]){ + parallax_layers_height = $def_height * 0.6; + }else if($window_width > responsive_breakpoint_set[3]){ + parallax_layers_height = $def_height * 0.55; + }else if($window_width <= responsive_breakpoint_set[3]){ + parallax_layers_height = $def_height * 0.45; + } + + $this.css({'height': (parallax_layers_height) + 'px'}); +} + +function parallaxLayers(){ + "use strict"; + + if($j('.qode_parallax_layers').length){ + + $j(".qode_parallax_layers").each(function(){ + + var $this = $j(this); + if($j(this).hasClass('full_screen_height')){ + $this.height($window_height); + $j(window).resize(function () { + $this.height($window_height); + }); + }else{ + var $def_height = $j(this).data('height'); + setParallaxLayersHeight($this, $def_height); + $j(window).resize(function () { + setParallaxLayersHeight($this, $def_height); + }); + } + + var $parallax_layers_holder = $this.find('.qode_parallax_layers_holder'); + var counter = 0; + var limit = $this.find(".image").length; + $this.find(".image").each(function() { + + var $this = $j(this); + if($this.css("background-image") != "" && $this.css("background-image") != "none") { + + var bg_url = $this.attr('style'); + + bg_url = bg_url.match(/url\(["']?([^'")]+)['"]?\)/); + bg_url = bg_url ? bg_url[1] : ""; + if (bg_url) { + var backImg = new Image(); + backImg.src = bg_url; + $j(backImg).load(function(){ + counter++; + if(counter == limit){ + $parallax_layers_holder.removeClass('preload_parallax_layers'); + if($j('html').hasClass('no-touch')){$parallax_layers_holder.mouseParallax()}; + } + }); + } + } + }); + }); + + } +} + +function alterWPMLSwitcherHeaderBottom() { + "use strict"; + + if($j('.header_bottom .main_menu li.menu-item-language').length) { + var langDropdown = $j('.header_bottom .main_menu .menu-item-language').find('.submenu-languages'); + + if(typeof langDropdown !== 'undefined') { + langDropdown.parent('li').addClass('narrow'); + langDropdown.wrap('
      '); + langDropdown.show(); + } + } + + if($j('.header_bottom .mobile_menu li.menu-item-language').length) { + var langDropdown = $j('.header_bottom .mobile_menu .menu-item-language').find('.submenu-languages'); + + if(typeof langDropdown !== 'undefined') { + langDropdown.parent('li').addClass('has_sub'); + langDropdown.prev('a').after(''); + langDropdown.addClass('sub_menu'); + } + + } +} diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/client-rcml.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/client-rcml.adoc new file mode 100644 index 0000000000..758a0ad1ac --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/client-rcml.adoc @@ -0,0 +1,165 @@ += Restcomm RCML – Client + +[[client]] +== Client + +[[attributes]] +=== Noun Attributes + +The `` noun supports the following attributes that modify its behavior: + +[cols=",,",options="header",] +|========================================================================== +|Attribute Name |Allowed Values |Default Value +|name |String |none +|url |any url |none +|method |`GET`, `POST` |`POST` +|statusCallbackEvent |`initiated`, `ringing`, `answered`, `completed` |none +|statusCallback |any url |none +|statusCallbackMethod |`GET`, `POST` |`POST` +|========================================================================== + +==== name + +The 'name' attribute allows you to inform the client who will answer to a video call. This attribute should be used only when `
      gvagenas + * + */ +public class ExtensionResponse { + private Object object; + private boolean allowed = true; + + public ExtensionResponse() {} + + public Object getObject() { + return object; + } + + public void setObject(Object object) { + this.object = object; + } + + public boolean isAllowed() { + return allowed; + } + + public void setAllowed(boolean allowed) { + this.allowed = allowed; + } +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionType.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionType.java new file mode 100644 index 0000000000..753efd0b3d --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionType.java @@ -0,0 +1,29 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +/** + * @author gvagenas + * + */ +public enum ExtensionType { +CallManager, SmsService, UssdCallManager,RestApi, FeatureAccessControl +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateCallRequest.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateCallRequest.java new file mode 100755 index 0000000000..f88ea24199 --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateCallRequest.java @@ -0,0 +1,85 @@ +package org.restcomm.connect.extension.api; + +import java.util.ArrayList; +import java.util.Map; + +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.telephony.CreateCallType; + +public interface IExtensionCreateCallRequest extends IExtensionRequest { + + /** + * @return the from address + */ + String getFrom(); + + /** + * @return the to address + */ + String getTo(); + + /** + * @return the accountId + */ + Sid getAccountId(); + + /** + * @return boolean if is from EP + */ + boolean isFromApi(); + + /** + * @return boolean if this is a child call + */ + boolean isParentCallSidExists(); + + /** + * @return the CreateCallType + */ + CreateCallType getType(); + + /** + * @return the outboundProxy + */ + String getOutboundProxy(); + + /** + * @param outboundProxy the outboundProxy to set + */ + void setOutboundProxy(String outboundProxy); + + /** + * @return the outboundProxyUsername + */ + String getOutboundProxyUsername(); + + /** + * @param outboundProxyUsername the outboundProxyUsername to set + */ + void setOutboundProxyUsername(String outboundProxyUsername); + + /** + * @return the outboundProxyPassword + */ + String getOutboundProxyPassword(); + + /** + * @param outboundProxyPassword the outboundProxyPassword to set + */ + void setOutboundProxyPassword(String outboundProxyPassword); + + /** + * @return the outboundProxyHeaders + */ + Map> getOutboundProxyHeaders(); + + /** + * @param outboundProxyHeaders the outboundProxyHeaders to set + */ + void setOutboundProxyHeaders(Map> outboundProxyHeaders); + + /** + * @return the Request URI + */ + String getRequestURI(); +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateSmsSessionRequest.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateSmsSessionRequest.java new file mode 100755 index 0000000000..ad7dd73008 --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionCreateSmsSessionRequest.java @@ -0,0 +1,39 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +import org.apache.commons.configuration.Configuration; + +public interface IExtensionCreateSmsSessionRequest extends IExtensionRequest { + /** + * FIXME: potentially we will change this to be specific properties + * rather than a whole Config object + * @param set Configuration object + */ + void setConfiguration(Configuration configuration); + + /** + * FIXME: potentially we will change this to be specific properties + * rather than a whole Config object + * @return the Configuration object + */ + Configuration getConfiguration(); +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionFeatureAccessRequest.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionFeatureAccessRequest.java new file mode 100644 index 0000000000..d033ba9e90 --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionFeatureAccessRequest.java @@ -0,0 +1,34 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +import org.restcomm.connect.commons.dao.Sid; + +public interface IExtensionFeatureAccessRequest extends IExtensionRequest{ + + void setAccountSid (Sid accountSid); + + String getDestinationNumber(); + + void setDestinationNumber(String destinationNumber); + + +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionRequest.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionRequest.java new file mode 100755 index 0000000000..0211de62d6 --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/IExtensionRequest.java @@ -0,0 +1,40 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +public interface IExtensionRequest { + + /** + * @return the accountId as String + * FIXME: should this be at this level? + */ + String getAccountSid(); + + /** + * @return whether request should proceed + */ + boolean isAllowed(); + + /** + * @param set to allow/restrict request + */ + void setAllowed(boolean allowed); +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtension.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtension.java new file mode 100644 index 0000000000..352146d18a --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtension.java @@ -0,0 +1,38 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author gvagenas + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE}) +public @interface RestcommExtension { + String author(); + String version() default "1.0.0-SNAPSHOT"; + ExtensionType[] type(); +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionException.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionException.java new file mode 100644 index 0000000000..6f05c4fb9e --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionException.java @@ -0,0 +1,10 @@ +package org.restcomm.connect.extension.api; + +/** + * Created by gvagenas on 03/11/2016. + */ +public class RestcommExtensionException extends Exception { + public RestcommExtensionException(String message) { + super(message); + } +} diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java new file mode 100644 index 0000000000..129ed1ce7b --- /dev/null +++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java @@ -0,0 +1,91 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.api; + +import javax.servlet.ServletContext; + +/** + * @author gvagenas + * + */ +public interface RestcommExtensionGeneric { + /** + * Use this method to initialize the Extension + */ + void init(ServletContext context); + /** + * Check if extensions is enabled + * @return + */ + boolean isEnabled(); + /** + * Method that will be executed BEFORE the process of an Incoming session + * Implement this method so you will be able to check the Incoming session + * and either block/allow or modify the session before Restcomm process it + * @return ExtensionResponse see ExtensionResponse + */ + ExtensionResponse preInboundAction(IExtensionRequest extensionRequest); + /** + * Method that will be executed AFTER the process of an Incoming session + * Implement this method so you will be able to check the Incoming session + * and either block or allow or modify the session after Restcomm process it + * @return ExtensionResponse see ExtensionResponse + */ + ExtensionResponse postInboundAction(IExtensionRequest extensionRequest); + /** + * Method that will be executed before the process of an Outbound session + * Implement this method so you will be able to check the Outbound session + * and either block/allow it or modify the session before Restcomm process it + * @return ExtensionResponse see ExtensionResponse + */ + ExtensionResponse preOutboundAction(IExtensionRequest extensionRequest); + /** + * Method that will be executed AFTER the process of an Outbound session + * Implement this method so you will be able to check the Outgoing session + * and either block or allow or modify the session after Restcomm process it + * @return ExtensionResponse see ExtensionResponse + */ + ExtensionResponse postOutboundAction(IExtensionRequest extensionRequest); + + /** + * Method that will be executed before the process of an API action, such as DID purchase (but after security checks) + * @return ExtensionResponse see ExtensionResponse + */ + ExtensionResponse preApiAction(ApiRequest apiRequest); + + /** + * Method that will be executed after the process of an API action, such as DID purchase + * @return + */ + ExtensionResponse postApiAction(ApiRequest apiRequest); + + /** + * Extension name getter + * @return String name of Extension + */ + String getName(); + + /** + * Extension version getter + * @return String version of Extension + */ + String getVersion(); +} diff --git a/restcomm/restcomm.extension.controller/pom.xml b/restcomm/restcomm.extension.controller/pom.xml new file mode 100644 index 0000000000..65a74002f4 --- /dev/null +++ b/restcomm/restcomm.extension.controller/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT + + + org.restcomm + restcomm-connect.extension.controller + restcomm-connect.extension.controller + + + UTF-8 + + + + + org.slf4j + slf4j-api + + + + org.slf4j + slf4j-log4j12 + + + + commons-configuration + commons-configuration + + + + org.restcomm + restcomm-connect.extension.api + ${project.version} + + + + org.mobicents.servlet.sip + sip-servlets-spec + ${sipservletapi.version} + provided + + + + org.apache.tomcat + tomcat-coyote + provided + + + + org.restcomm + restcomm-connect.dao + ${project.version} + + + org.restcomm + restcomm-connect.commons + ${project.version} + + + org.apache.maven + maven-artifact + + + + diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java new file mode 100755 index 0000000000..a1306d1cbe --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java @@ -0,0 +1,266 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.extension.configuration; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.util.HashMap; + +import java.util.Map; + +import org.apache.ibatis.exceptions.PersistenceException; +import org.apache.log4j.Logger; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.api.ExtensionConfiguration; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; + +public class DefaultExtensionConfiguration { + public enum PropertyType { + VERSION("version"); + private String value; + + private PropertyType(String value) { + this.value = value; + } + }; + + private static final Logger logger = Logger.getLogger(DefaultExtensionConfiguration.class); + private boolean workingWithLocalConf; + private ExtensionsConfigurationDao extensionConfigurationDao; + private ExtensionConfiguration extensionConfiguration; + private JsonObject configurationJsonObj; + private JsonParser jsonParser; + private DaoManager daoManager; + private Gson gson; + private JsonObject defaultConfigurationJsonObj; + private String extensionName; + private DefaultArtifactVersion defVersion; + private HashMap specificConfigurationMap; + private Sid sid; + private String localConfigPath; + + public DefaultExtensionConfiguration() { + this.sid = new Sid("EX00000000000000000000000000000001"); + this.localConfigPath = ""; + } + + public DefaultExtensionConfiguration(final DaoManager daoManager, String extensionName, String localConfigPath) { + try { + init(daoManager, extensionName, localConfigPath); + } catch (Exception e) { + logger.error("Exception initializing"); + } + } + + public void init(final DaoManager daoManager, String extensionName, String localConfigPath) throws ConfigurationException { + try { + this.setDaoManager(daoManager); + this.extensionConfigurationDao = daoManager.getExtensionsConfigurationDao(); + + if (extensionName.isEmpty() && localConfigPath.isEmpty()) { + throw new ConfigurationException("extensionName or local config cant be empty"); + } + if (!extensionName.isEmpty()) { + this.extensionName = extensionName; + } + if (!localConfigPath.isEmpty()) { + // Load the default extensionConfiguration from file + this.defaultConfigurationJsonObj = loadDefaultConfiguration(localConfigPath); + + configurationJsonObj = this.defaultConfigurationJsonObj; + + // Get the extension name from default extensionConfiguration + String temp = defaultConfigurationJsonObj.get("extension_name").getAsString(); + if (!temp.isEmpty()) { + extensionName = temp; + } + defVersion = new DefaultArtifactVersion(defaultConfigurationJsonObj.get("version").getAsString()); + } + // Load extensionConfiguration from DB + extensionConfiguration = extensionConfigurationDao.getConfigurationByName(extensionName); + + // try fetch sid from name + if (extensionConfiguration == null) { + // If extensionConfiguration from DB is null then add the default values to DB + this.sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + extensionConfiguration = new ExtensionConfiguration(sid, this.extensionName, true, + defaultConfigurationJsonObj.toString(), ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionConfigurationDao.addConfiguration(extensionConfiguration); + + } else { + // Get configuration object + this.sid = extensionConfiguration.getSid(); + // try get default config data + JsonObject dbConfiguration = null; + + DefaultArtifactVersion currentVersion = null; + try { + dbConfiguration = (JsonObject) jsonParser.parse((String) extensionConfiguration.getConfigurationData()); + if (dbConfiguration.get("version") != null) { + currentVersion = new DefaultArtifactVersion(dbConfiguration.get("version").getAsString()); + } + + if (dbConfiguration != null && (currentVersion == null || currentVersion.compareTo(defVersion) < 0)) { + if (logger.isInfoEnabled()) { + logger.info("Configuration found in the DB is older version than the default one: " + + defVersion.toString()); + } + + for (Map.Entry jsonElementEntry : defaultConfigurationJsonObj.entrySet()) { + if (!jsonElementEntry.getKey().equalsIgnoreCase("specifics_configuration") + && dbConfiguration.get(jsonElementEntry.getKey()) == null) { + dbConfiguration.add(jsonElementEntry.getKey(), jsonElementEntry.getValue()); + } + } + if (dbConfiguration.get("version") != null) { + dbConfiguration.remove("version"); + } + dbConfiguration.addProperty("version", defaultConfigurationJsonObj.get("version").getAsString()); + + extensionConfiguration = new ExtensionConfiguration(extensionConfiguration.getSid(), extensionName, + extensionConfiguration.isEnabled(), dbConfiguration.toString(), + ExtensionConfiguration.configurationType.JSON, DateTime.now()); + extensionConfigurationDao.updateConfiguration(extensionConfiguration); + } + configurationJsonObj = dbConfiguration; + // Load Specific Configuration Map + // loadSpecificConfigurationMap(configurationJsonObj); + } catch (Exception e) { + } + + } + if (logger.isInfoEnabled()) { + logger.info("Finished loading configuration for extension: " + extensionName); + } + } catch (ConfigurationException configurationException) { + String errorMessage = "Exception during " + this.getClass() + " Configuration constructor "; + if (logger.isDebugEnabled()) { + logger.debug(errorMessage + configurationException); + } + throw new ConfigurationException(errorMessage); + } catch (PersistenceException persistenceException) { + if (logger.isDebugEnabled()) { + logger.debug("PersistenceException during " + this.getClass() + " init, will fallback to default configuration"); + } + workingWithLocalConf = true; + } catch (IOException e) { + logger.debug("IOException during " + this.getClass()); + } + } + + public JsonObject loadDefaultConfiguration(String localConfigFilePath) throws IOException { + JsonObject jsonObj = null; + jsonParser = new JsonParser(); + InputStream in = (InputStream) getClass().getResourceAsStream(localConfigFilePath); + BufferedReader inReader = new BufferedReader(new InputStreamReader(in)); + JsonReader reader = new JsonReader(inReader); + JsonElement jsonElement = jsonParser.parse(reader); + jsonObj = (JsonObject) jsonElement; + in.close(); + inReader.close(); + reader.close(); + return jsonObj; + } + + public void reloadConfiguration() { + if (!workingWithLocalConf) { + if (extensionConfigurationDao.isLatestVersionByName(extensionName, extensionConfiguration.getDateUpdated())) { + extensionConfiguration = extensionConfigurationDao.getConfigurationByName(extensionName); + String updatedConf = (String) extensionConfiguration.getConfigurationData(); + configurationJsonObj = (JsonObject) jsonParser.parse(updatedConf); + // loadSpecificConfigurationMap(configurationJsonObj); + if (logger.isInfoEnabled()) { + logger.info(this.extensionName + " extension configuration reloaded"); + } + } + } + } + + public boolean isEnabled() { + reloadConfiguration(); + if (extensionConfiguration != null) { + return extensionConfiguration.isEnabled(); + } else { + return true; + } + } + + public String getVersion() { + reloadConfiguration(); + String ver = configurationJsonObj.get(PropertyType.VERSION.value).getAsString(); + return ver; + } + + public Sid getSid() { + return this.sid; + } + + public void loadSpecificConfigurationMap(final JsonObject json) { + JsonArray specificConfJsonArray = json.getAsJsonArray(); + // JsonArray specificConfJsonArray = json.getAsJsonArray("specifics_configuration"); + // if (specificConfJsonArray != null) { + // specificConfigurationMap = new HashMap(); + // Iterator iter = specificConfJsonArray.iterator(); + // while (iter.hasNext()) { + // JsonElement elem = iter.next(); + // if (elem.getAsJsonObject().get("sid") != null) { + // specificConfigurationMap.put(sid, value); + // } + // } + // } + // return map + } + + // getConfigAsJson + // getConfigAsConfiguration + // getConfigAsHashMap + /*public void getSpecificConfigurationMapAsXml() { + }*/ + + /** + * @return the daoManager + */ + public DaoManager getDaoManager() { + return daoManager; + } + + /** + * @param daoManager the daoManager to set + */ + public void setDaoManager(DaoManager daoManager) { + this.daoManager = daoManager; + } + + public JsonObject getCurrentConf() { + return configurationJsonObj; + } +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionBootstrapper.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionBootstrapper.java new file mode 100644 index 0000000000..2b498a3756 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionBootstrapper.java @@ -0,0 +1,77 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.extension.controller; + +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.HierarchicalConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Logger; + +import javax.servlet.ServletContext; +import java.util.ArrayList; +import java.util.List; + +/** + * @author gvagenas + * + */ +public class ExtensionBootstrapper { + private Logger logger = Logger.getLogger(ExtensionBootstrapper.class); + private Configuration configuration; + private ServletContext context; + List extensions = new ArrayList(); + + public ExtensionBootstrapper(final ServletContext context, final Configuration configuration) { + this.configuration = configuration; + this.context = context; + } + + public void start() throws ClassNotFoundException, IllegalAccessException, InstantiationException { + + List exts = ((XMLConfiguration)configuration).configurationsAt("extensions.extension"); + + for (HierarchicalConfiguration ext: exts) { + String name = ext.getString("[@name]"); + String className = ext.getString("class"); + boolean enabled = ext.getBoolean("enabled"); + if (enabled) { + try { + Class klass = (Class) Class.forName(className); + RestcommExtensionGeneric extension = klass.newInstance(); + extension.init(this.context); + + //Store it in the context using the extension name + context.setAttribute(name, extension); + ExtensionController.getInstance().registerExtension(extension); + if (logger.isInfoEnabled()) { + logger.info("Stated Extension: " + name); + } + } catch (Exception e) { + if (logger.isInfoEnabled()) { + logger.info("Exception during initialization of extension \""+name+"\", exception: "+e.getStackTrace()); + } + } + } + } + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java new file mode 100644 index 0000000000..df44937801 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java @@ -0,0 +1,285 @@ +package org.restcomm.connect.extension.controller; + +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.apache.log4j.Logger; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Created by gvagenas on 21/09/16. + */ +public class ExtensionController { + private static Logger logger = Logger.getLogger(ExtensionController.class); + + private static ExtensionController instance; + private List callManagerExtensions; + private List smsSessionExtensions; + private List ussdCallManagerExtensions; + private List restApiExtensions; + private List featureAccessControlExtensions; + + private ExtensionController(){ + this.callManagerExtensions = new CopyOnWriteArrayList(); + this.smsSessionExtensions = new CopyOnWriteArrayList(); + this.ussdCallManagerExtensions = new CopyOnWriteArrayList(); + this.restApiExtensions = new CopyOnWriteArrayList(); + this.featureAccessControlExtensions = new CopyOnWriteArrayList(); + } + + public static ExtensionController getInstance() { + if (instance == null) { + instance = new ExtensionController(); + } + return instance; + } + + /** + * allow to reset the singleton. Mainly for testing purposes. + * TODO should we reset the singleton if app is shutdown...? + */ + public void reset() { + instance = null; + } + + public List getExtensions(final ExtensionType type) { + //Check the sender's class and return the extensions that are supported for this class + if (type.equals(ExtensionType.CallManager) && (callManagerExtensions != null && callManagerExtensions.size() > 0)) { + return callManagerExtensions; + } else if (type.equals(ExtensionType.SmsService) && (smsSessionExtensions != null && smsSessionExtensions.size() > 0)) { + return smsSessionExtensions; + } else if (type.equals(ExtensionType.UssdCallManager) && (ussdCallManagerExtensions != null && ussdCallManagerExtensions.size() > 0)) { + return ussdCallManagerExtensions; + } else if (type.equals(ExtensionType.RestApi) && (restApiExtensions != null && restApiExtensions.size() > 0)) { + return restApiExtensions; + } else if (type.equals(ExtensionType.FeatureAccessControl) && (featureAccessControlExtensions != null && featureAccessControlExtensions.size() > 0)) { + return featureAccessControlExtensions; + } else { + return null; + } + } + + public void registerExtension(final RestcommExtensionGeneric extension) { + //scan the annotation to see what this extension supports + ExtensionType[] types = extension.getClass().getAnnotation(RestcommExtension.class).type(); + String extensionName = extension.getClass().getName(); + for (ExtensionType type : types) { + if (type.equals(ExtensionType.CallManager)) { + callManagerExtensions.add(extension); + if (logger.isDebugEnabled()) { + logger.debug("CallManager extension added: "+extensionName); + } + } + if (type.equals(ExtensionType.SmsService)) { + smsSessionExtensions.add(extension); + if (logger.isDebugEnabled()) { + logger.debug("SmsService extension added: "+extensionName); + } + } + if (type.equals(ExtensionType.UssdCallManager)) { + ussdCallManagerExtensions.add(extension); + if (logger.isDebugEnabled()) { + logger.debug("UssdCallManager extension added: "+extensionName); + } + } + if (type.equals(ExtensionType.RestApi)) { + restApiExtensions.add(extension); + if (logger.isDebugEnabled()) { + logger.debug("RestApi extension added: "+extensionName); + } + } + if (type.equals(ExtensionType.FeatureAccessControl)) { + featureAccessControlExtensions.add(extension); + if (logger.isDebugEnabled()) { + logger.debug("FeatureAccesControl extension added: "+extensionName); + } + } + } + } + + public ExtensionResponse executePreOutboundAction(final IExtensionRequest ier, List extensions) { + //FIXME: if we have more than one extension in chain + // and all of them are successful, we only receive the last + // extensionResponse + ExtensionResponse response = new ExtensionResponse(); + if (extensions != null && extensions.size() > 0) { + + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.preOutboundAction(ier); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } + + public ExtensionResponse executePostOutboundAction(final IExtensionRequest er, List extensions) { + ExtensionResponse response = new ExtensionResponse(); + if (extensions != null && extensions.size() > 0) { + + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.postOutboundAction(er); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } + + public ExtensionResponse executePreInboundAction(final IExtensionRequest er, List extensions) { + ExtensionResponse response = new ExtensionResponse(); + if (extensions != null && extensions.size() > 0) { + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.preInboundAction(er); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } + + public ExtensionResponse executePostInboundAction(final IExtensionRequest er, List extensions) { + ExtensionResponse response = new ExtensionResponse(); + if (extensions != null && extensions.size() > 0) { + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.postInboundAction(er); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } + + public ExtensionResponse executePreApiAction(final ApiRequest apiRequest, List extensions) { + ExtensionResponse response = new ExtensionResponse(); + + if (extensions != null && extensions.size() > 0) { + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.preApiAction(apiRequest); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } + + public ExtensionResponse executePostApiAction(final ApiRequest apiRequest, List extensions) { + ExtensionResponse response = new ExtensionResponse(); + + if (extensions != null && extensions.size() > 0) { + for (RestcommExtensionGeneric extension : extensions) { + if(logger.isInfoEnabled()) { + logger.info( extension.getName()+" is enabled="+extension.isEnabled()); + } + if (extension.isEnabled()) { + try { + ExtensionResponse tempResponse = extension.postApiAction(apiRequest); + if (tempResponse != null) { + response = tempResponse; + //fail fast + if (!tempResponse.isAllowed()) { + break; + } + } + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + String msg = String.format("There was an exception while executing preInboundAction from extension %s", extension.getName()); + logger.debug(msg, t); + } + } + } + } + } + return response; + } +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/AllowingExtensionMock.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/AllowingExtensionMock.java new file mode 100644 index 0000000000..197c7f1a32 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/AllowingExtensionMock.java @@ -0,0 +1,113 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; + +/** + * Extension that allows any execution point. Provided for testing purposes + * @author + */ +@RestcommExtension(author = "restcomm", version = "1.0.0.Alpha", type = {ExtensionType.CallManager, ExtensionType.SmsService, ExtensionType.UssdCallManager, ExtensionType.FeatureAccessControl, ExtensionType.RestApi}) +public class AllowingExtensionMock implements RestcommExtensionGeneric { + + private static Logger logger = Logger.getLogger(AllowingExtensionMock.class); + + private String extensionName = "allowing"; + private final String localConfigPath = "/allowing_default_configuration.json"; + private MockConfiguration config; + + @Override + public void init(ServletContext context) { + try { + DaoManager daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + config = new MockConfiguration(daoManager, extensionName, localConfigPath); + config.init(daoManager, extensionName, localConfigPath); + } catch (Exception configurationException) { + logger.error("Exception during init", configurationException); + } + } + + @Override + public ExtensionResponse preInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse postInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse preOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse postOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse preApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse postApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public String getName() { + return this.extensionName; + } + + @Override + public String getVersion() { + return ((RestcommExtension) AllowingExtensionMock.class.getAnnotation(RestcommExtension.class)).version(); + } + + @Override + public boolean isEnabled() { + return config.isEnabled(); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/BlockingExtensionMock.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/BlockingExtensionMock.java new file mode 100644 index 0000000000..9ae230cf6d --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/BlockingExtensionMock.java @@ -0,0 +1,113 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; + +/** + * Extension that rejects any execution point. Provided for testing purposes + * @author + */ +@RestcommExtension(author = "restcomm", version = "1.0.0.Alpha", type = {ExtensionType.CallManager, ExtensionType.SmsService, ExtensionType.UssdCallManager, ExtensionType.FeatureAccessControl, ExtensionType.RestApi}) +public class BlockingExtensionMock implements RestcommExtensionGeneric { + + private static Logger logger = Logger.getLogger(BlockingExtensionMock.class); + + private String extensionName = "blocking"; + private final String localConfigPath = "/blocking_default_configuration.json"; + private MockConfiguration config; + + @Override + public void init(ServletContext context) { + try { + DaoManager daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + config = new MockConfiguration(daoManager, extensionName, localConfigPath); + config.init(daoManager, extensionName, localConfigPath); + } catch (Exception configurationException) { + logger.error("Exception during init", configurationException); + } + } + + @Override + public ExtensionResponse preInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse postInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse preOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse postOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse preApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse postApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public String getName() { + return this.extensionName; + } + + @Override + public String getVersion() { + return ((RestcommExtension) BlockingExtensionMock.class.getAnnotation(RestcommExtension.class)).version(); + } + + @Override + public boolean isEnabled() { + return config.isEnabled(); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/DBExtensionMock.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/DBExtensionMock.java new file mode 100644 index 0000000000..94feb8907d --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/DBExtensionMock.java @@ -0,0 +1,120 @@ +/* + * 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.extension.mock; + +import com.google.gson.JsonObject; +import javax.servlet.ServletContext; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; + +/** + * Extension that rejects any execution point. Provided for testing purposes + * @author + */ +@RestcommExtension(author = "restcomm", version = "1.0.0.Alpha", type = {ExtensionType.CallManager, ExtensionType.SmsService, ExtensionType.UssdCallManager, ExtensionType.FeatureAccessControl, ExtensionType.RestApi}) +public class DBExtensionMock implements RestcommExtensionGeneric { + + private static Logger logger = Logger.getLogger(DBExtensionMock.class); + + private String extensionName = "simple_db"; + private final String localConfigPath = "/simple_db_default_configuration.json"; + private MockConfiguration config; + + @Override + public void init(ServletContext context) { + try { + DaoManager daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + config = new MockConfiguration(daoManager, extensionName, localConfigPath); + config.init(daoManager, extensionName, localConfigPath); + } catch (Exception configurationException) { + logger.error("Exception during init", configurationException); + } + } + + private boolean queryRequestAllowed(String req) { + JsonObject currentConf = config.getCurrentConf(); + JsonObject jsonFound = currentConf.getAsJsonObject(req); + return jsonFound != null; + } + + @Override + public ExtensionResponse preInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("pre-inbound-" + extensionRequest.getClass().getSimpleName())); + return response; + } + + @Override + public ExtensionResponse postInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("post-inbound-" + extensionRequest.getClass().getSimpleName())); + return response; + } + + @Override + public ExtensionResponse preOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("pre-outbound-" + extensionRequest.getClass().getSimpleName())); + return response; + } + + @Override + public ExtensionResponse postOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("post-outbound-" + extensionRequest.getClass().getSimpleName())); + return response; + } + + @Override + public ExtensionResponse preApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("pre-api-" + apiRequest.getType())); + return response; + } + + @Override + public ExtensionResponse postApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(queryRequestAllowed("post-api-" + apiRequest.getType())); + return response; + } + + @Override + public String getName() { + return this.extensionName; + } + + @Override + public String getVersion() { + return ((RestcommExtension) DBExtensionMock.class.getAnnotation(RestcommExtension.class)).version(); + } + + @Override + public boolean isEnabled() { + return config.isEnabled(); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/MockConfiguration.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/MockConfiguration.java new file mode 100644 index 0000000000..071a878ade --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/MockConfiguration.java @@ -0,0 +1,39 @@ +/* + * 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.extension.mock; + +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.configuration.DefaultExtensionConfiguration; + + + +public class MockConfiguration extends DefaultExtensionConfiguration{ + + public MockConfiguration(){ + super(); + } + public MockConfiguration(DaoManager daoManager, String extensionName, String localConfigPath) + throws ConfigurationException { + super(daoManager, extensionName, localConfigPath); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMock.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMock.java new file mode 100644 index 0000000000..604a79694a --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMock.java @@ -0,0 +1,113 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; + +/** + * Extension that rejects any execution point. Provided for testing purposes + * @author + */ +@RestcommExtension(author = "restcomm", version = "1.0.0.Alpha", type = {ExtensionType.CallManager, ExtensionType.SmsService, ExtensionType.UssdCallManager, ExtensionType.FeatureAccessControl, ExtensionType.RestApi}) +public class OutboundBlockingExtensionMock implements RestcommExtensionGeneric { + + private static Logger logger = Logger.getLogger(OutboundBlockingExtensionMock.class); + + private String extensionName = "outbound_blocking"; + private final String localConfigPath = "/outbound_blocking_default_configuration.json"; + private MockConfiguration config; + + @Override + public void init(ServletContext context) { + try { + DaoManager daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + config = new MockConfiguration(daoManager, extensionName, localConfigPath); + config.init(daoManager, extensionName, localConfigPath); + } catch (Exception configurationException) { + logger.error("Exception during init", configurationException); + } + } + + @Override + public ExtensionResponse preInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse postInboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse preOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse postOutboundAction(IExtensionRequest extensionRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(false); + return response; + } + + @Override + public ExtensionResponse preApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public ExtensionResponse postApiAction(ApiRequest apiRequest) { + ExtensionResponse response = new ExtensionResponse(); + response.setAllowed(true); + return response; + } + + @Override + public String getName() { + return this.extensionName; + } + + @Override + public String getVersion() { + return ((RestcommExtension) OutboundBlockingExtensionMock.class.getAnnotation(RestcommExtension.class)).version(); + } + + @Override + public boolean isEnabled() { + return config.isEnabled(); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/main/resources/allowing_default_configuration.json b/restcomm/restcomm.extension.controller/src/main/resources/allowing_default_configuration.json new file mode 100644 index 0000000000..606e0ed060 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/resources/allowing_default_configuration.json @@ -0,0 +1,4 @@ +{ + "extension_name": "allowing", + "version": "1.0.0" +} diff --git a/restcomm/restcomm.extension.controller/src/main/resources/blocking_default_configuration.json b/restcomm/restcomm.extension.controller/src/main/resources/blocking_default_configuration.json new file mode 100644 index 0000000000..631c929e5a --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/resources/blocking_default_configuration.json @@ -0,0 +1,4 @@ +{ + "extension_name": "blocking", + "version": "1.0.0" +} diff --git a/restcomm/restcomm.extension.controller/src/main/resources/outbound_blocking_default_configuration.json b/restcomm/restcomm.extension.controller/src/main/resources/outbound_blocking_default_configuration.json new file mode 100644 index 0000000000..6b33f96085 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/resources/outbound_blocking_default_configuration.json @@ -0,0 +1,4 @@ +{ + "extension_name": "outbound_blocking", + "version": "1.0.0" +} diff --git a/restcomm/restcomm.extension.controller/src/main/resources/simple_db_default_configuration.json b/restcomm/restcomm.extension.controller/src/main/resources/simple_db_default_configuration.json new file mode 100644 index 0000000000..a5eaffd126 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/main/resources/simple_db_default_configuration.json @@ -0,0 +1,14 @@ +{ + "extension_name": "simple_db", + "version": "1.0.0", + "pre-api-CREATE_SUBACCOUNT": {}, + "post-api-CREATE_SUBACCOUNT": {}, + "pre-api-AVAILABLEPHONENUMBER": {}, + "post-api-AVAILABLEPHONENUMBER": {}, + "pre-api-INCOMINGPHONENUMBER": {}, + "post-api-INCOMINGPHONENUMBER": {}, + "pre-inbound-ExtensionRequest": {}, + "post-inbound-ExtensionRequest": {}, + "pre-outbound-ExtensionRequest": {}, + "post-outbound-ExtensionRequest": {} +} diff --git a/restcomm/restcomm.extension.controller/src/test/java/org.restcomm.connect.extension.controller/ExtensionsControllerTest.java b/restcomm/restcomm.extension.controller/src/test/java/org.restcomm.connect.extension.controller/ExtensionsControllerTest.java new file mode 100644 index 0000000000..b14902e45d --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/java/org.restcomm.connect.extension.controller/ExtensionsControllerTest.java @@ -0,0 +1,213 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2018, 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.extension.controller; + +import org.apache.log4j.Logger; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.restcomm.connect.commons.annotations.UnstableTests; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.extension.api.ApiRequest; +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.IExtensionRequest; +import org.restcomm.connect.extension.api.RestcommExtension; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; + +import javax.servlet.ServletContext; +import java.util.List; +import org.junit.After; + +public class ExtensionsControllerTest { + + private static Logger logger = Logger.getLogger(ExtensionsControllerTest.class); + + private RestcommExtensionGeneric testExtension = new TestExtension(); + + @After + public void resteController() { + //reset the singleton after each test to provide isolation and + //predictibiltiy when full test class is executed + ExtensionController.getInstance().reset(); + } + + @Test + public void extensionRegistry() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List callManagerExts = extensionController.getExtensions(ExtensionType.CallManager); + logger.info("CallManagerExtensions list size: "+callManagerExts.size()); + for (RestcommExtensionGeneric ext: callManagerExts) { + logger.info("ExtensionName: "+ext.getName()); + } + + Assert.assertEquals(1, callManagerExts.size()); + Assert.assertEquals(1, extensionController.getExtensions(ExtensionType.FeatureAccessControl).size()); + Assert.assertEquals(1, extensionController.getExtensions(ExtensionType.RestApi).size()); + Assert.assertEquals(1, extensionController.getExtensions(ExtensionType.SmsService).size()); + Assert.assertEquals(1, extensionController.getExtensions(ExtensionType.UssdCallManager).size()); + } + + @Test + public void preInboundActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + IExtensionRequest request = new ExtensionRequest(); + + ExtensionResponse er = extensionController.executePreInboundAction(request, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + @Test + public void postInboundActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + IExtensionRequest request = new ExtensionRequest(); + + ExtensionResponse er = extensionController.executePostInboundAction(request, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + + @Test + public void preOutboundActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + IExtensionRequest request = new ExtensionRequest(); + + ExtensionResponse er = extensionController.executePreOutboundAction(request, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + @Test + public void postOutboundActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + IExtensionRequest request = new ExtensionRequest(); + + ExtensionResponse er = extensionController.executePostOutboundAction(request, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + @Test + public void preApiActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + Sid accSid = Sid.generate(Sid.Type.ACCOUNT); + ApiRequest apiRequest = new ApiRequest(accSid.toString(), null, ApiRequest.Type.CREATE_SUBACCOUNT); + + ExtensionResponse er = extensionController.executePreApiAction(apiRequest, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + @Test + public void postApiActionTest() { + ExtensionController extensionController = ExtensionController.getInstance(); + extensionController.registerExtension(testExtension); + + List extensions = extensionController.getExtensions(ExtensionType.FeatureAccessControl); + + Sid accSid = Sid.generate(Sid.Type.ACCOUNT); + ApiRequest apiRequest = new ApiRequest(accSid.toString(), null, ApiRequest.Type.CREATE_SUBACCOUNT); + + ExtensionResponse er = extensionController.executePostApiAction(apiRequest, extensions); + Assert.assertNotNull(er); + Assert.assertTrue(er.isAllowed()); + } + + @RestcommExtension(author = "TestExtension", version = "1.0.0.Alpha", type = {ExtensionType.CallManager, ExtensionType.SmsService, ExtensionType.UssdCallManager, ExtensionType.FeatureAccessControl, ExtensionType.RestApi}) + private class TestExtension implements RestcommExtensionGeneric { + + @Override + public void init (ServletContext context) { + + } + + @Override + public boolean isEnabled () { + return true; + } + + @Override + public ExtensionResponse preInboundAction (IExtensionRequest extensionRequest) { + return null; + } + + @Override + public ExtensionResponse postInboundAction (IExtensionRequest extensionRequest) { + return null; + } + + @Override + public ExtensionResponse preOutboundAction (IExtensionRequest extensionRequest) { + return null; + } + + @Override + public ExtensionResponse postOutboundAction (IExtensionRequest extensionRequest) { + return null; + } + + @Override + public ExtensionResponse preApiAction (ApiRequest apiRequest) { + return null; + } + + @Override + public ExtensionResponse postApiAction (ApiRequest apiRequest) { + return null; + } + + @Override + public String getName () { + return "TestExtension"; + } + + @Override + public String getVersion () { + return null; + } + } + +} diff --git a/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/AllowingExtensionMockTest.java b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/AllowingExtensionMockTest.java new file mode 100644 index 0000000000..b52c974517 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/AllowingExtensionMockTest.java @@ -0,0 +1,86 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import static org.mockito.Mockito.when; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; + +/** + * + * @author + */ + + +public class AllowingExtensionMockTest { + + public AllowingExtensionMockTest() { + } + class ExtensionCollaborators { + + ServletContext sCtx = Mockito.mock(ServletContext.class); + DaoManager daoMng = Mockito.mock(DaoManager.class); + ExtensionsConfigurationDao extDao = Mockito.mock(ExtensionsConfigurationDao.class); + + + public ExtensionCollaborators() { + when(sCtx.getAttribute(DaoManager.class.getName())). + thenReturn(daoMng); + when(daoMng.getExtensionsConfigurationDao()). + thenReturn(extDao); + when(extDao.getConfigurationByName("allowing")).thenReturn(null); + } + } + + @Test + public void testAllowingExtension() throws Exception { + ExtensionCollaborators mocks = new ExtensionCollaborators(); + AllowingExtensionMock extension = new AllowingExtensionMock(); + extension.init(mocks.sCtx); + + final ExtensionRequest far = new ExtensionRequest("aacountSid", true); + ExtensionResponse response = extension.preInboundAction(far); + Assert.assertTrue(response.isAllowed()); + response = extension.postInboundAction(far); + Assert.assertTrue(response.isAllowed()); + + response = extension.preOutboundAction(far); + Assert.assertTrue(response.isAllowed()); + response = extension.postOutboundAction(far); + Assert.assertTrue(response.isAllowed()); + + ApiRequest apiReq = new ApiRequest("aacountSid", null, ApiRequest.Type.CREATE_SUBACCOUNT); + response = extension.preApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + response = extension.postApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + + + } + +} diff --git a/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/BlockingExtensionMockTest.java b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/BlockingExtensionMockTest.java new file mode 100644 index 0000000000..afa8f5d683 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/BlockingExtensionMockTest.java @@ -0,0 +1,84 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import static org.mockito.Mockito.when; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; + +/** + * + * @author + */ + + +public class BlockingExtensionMockTest { + + public BlockingExtensionMockTest() { + } + class ExtensionCollaborators { + + ServletContext sCtx = Mockito.mock(ServletContext.class); + DaoManager daoMng = Mockito.mock(DaoManager.class); + ExtensionsConfigurationDao extDao = Mockito.mock(ExtensionsConfigurationDao.class); + + + public ExtensionCollaborators() { + when(sCtx.getAttribute(DaoManager.class.getName())). + thenReturn(daoMng); + when(daoMng.getExtensionsConfigurationDao()). + thenReturn(extDao); + when(extDao.getConfigurationByName("blocking")).thenReturn(null); + } + } + + @Test + public void testAllowingExtension() throws Exception { + ExtensionCollaborators mocks = new ExtensionCollaborators(); + BlockingExtensionMock extension = new BlockingExtensionMock(); + extension.init(mocks.sCtx); + + final ExtensionRequest far = new ExtensionRequest("accountSid", true); + ExtensionResponse response = extension.preInboundAction(far); + Assert.assertFalse(response.isAllowed()); + response = extension.postInboundAction(far); + Assert.assertFalse(response.isAllowed()); + + response = extension.preOutboundAction(far); + Assert.assertFalse(response.isAllowed()); + response = extension.postOutboundAction(far); + Assert.assertFalse(response.isAllowed()); + + ApiRequest apiReq = new ApiRequest("accountSid", null, ApiRequest.Type.CREATE_SUBACCOUNT); + response = extension.preApiAction(apiReq); + Assert.assertFalse(response.isAllowed()); + response = extension.postApiAction(apiReq); + Assert.assertFalse(response.isAllowed()); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/DBExtensionMockTest.java b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/DBExtensionMockTest.java new file mode 100644 index 0000000000..3bf252e3a8 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/DBExtensionMockTest.java @@ -0,0 +1,97 @@ +/* + * 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.extension.mock; + +import java.util.Calendar; +import javax.servlet.ServletContext; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import static org.mockito.Mockito.when; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionConfiguration; +import static org.restcomm.connect.extension.api.ExtensionConfiguration.configurationType.JSON; +import org.restcomm.connect.extension.api.ExtensionRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; + +/** + * + * @author + */ + + +public class DBExtensionMockTest { + + private static final String EXT_CONF="{}"; + public DBExtensionMockTest() { + } + class ExtensionCollaborators { + + ServletContext sCtx = Mockito.mock(ServletContext.class); + DaoManager daoMng = Mockito.mock(DaoManager.class); + ExtensionsConfigurationDao extDao = Mockito.mock(ExtensionsConfigurationDao.class); + + + public ExtensionCollaborators(String confJson) { + when(sCtx.getAttribute(DaoManager.class.getName())). + thenReturn(daoMng); + when(daoMng.getExtensionsConfigurationDao()). + thenReturn(extDao); + ExtensionConfiguration extConf = new ExtensionConfiguration(Sid. + generate(Sid.Type.EXTENSION_CONFIGURATION), + "simple_db", + true, + confJson, + JSON, + new DateTime(),new DateTime()); + when(extDao.getConfigurationByName("simple_db")).thenReturn(null); + } + } + + @Test + public void testAllowingExtension() throws Exception { + ExtensionCollaborators mocks = new ExtensionCollaborators(EXT_CONF); + DBExtensionMock extension = new DBExtensionMock(); + extension.init(mocks.sCtx); + + final ExtensionRequest far = new ExtensionRequest("accountSid", true); + ExtensionResponse response = extension.preInboundAction(far); + Assert.assertTrue(response.isAllowed()); + response = extension.postInboundAction(far); + Assert.assertTrue(response.isAllowed()); + + response = extension.preOutboundAction(far); + Assert.assertTrue(response.isAllowed()); + response = extension.postOutboundAction(far); + Assert.assertTrue(response.isAllowed()); + + ApiRequest apiReq = new ApiRequest("accountSid", null, ApiRequest.Type.CREATE_SUBACCOUNT); + response = extension.preApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + response = extension.postApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMockTest.java b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMockTest.java new file mode 100644 index 0000000000..ffce8ff75a --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/java/org/restcomm/connect/extension/mock/OutboundBlockingExtensionMockTest.java @@ -0,0 +1,84 @@ +/* + * 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.extension.mock; + +import javax.servlet.ServletContext; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import static org.mockito.Mockito.when; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionRequest; +import org.restcomm.connect.extension.api.ExtensionResponse; + +/** + * + * @author + */ + + +public class OutboundBlockingExtensionMockTest { + + public OutboundBlockingExtensionMockTest() { + } + class ExtensionCollaborators { + + ServletContext sCtx = Mockito.mock(ServletContext.class); + DaoManager daoMng = Mockito.mock(DaoManager.class); + ExtensionsConfigurationDao extDao = Mockito.mock(ExtensionsConfigurationDao.class); + + + public ExtensionCollaborators() { + when(sCtx.getAttribute(DaoManager.class.getName())). + thenReturn(daoMng); + when(daoMng.getExtensionsConfigurationDao()). + thenReturn(extDao); + when(extDao.getConfigurationByName("outbound_blocking")).thenReturn(null); + } + } + + @Test + public void testExtension() throws Exception { + ExtensionCollaborators mocks = new ExtensionCollaborators(); + OutboundBlockingExtensionMock extension = new OutboundBlockingExtensionMock(); + extension.init(mocks.sCtx); + + final ExtensionRequest far = new ExtensionRequest("accountSid", true); + ExtensionResponse response = extension.preInboundAction(far); + Assert.assertTrue(response.isAllowed()); + response = extension.postInboundAction(far); + Assert.assertTrue(response.isAllowed()); + + response = extension.preOutboundAction(far); + Assert.assertFalse(response.isAllowed()); + response = extension.postOutboundAction(far); + Assert.assertFalse(response.isAllowed()); + + ApiRequest apiReq = new ApiRequest("accountSid", null, ApiRequest.Type.CREATE_SUBACCOUNT); + response = extension.preApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + response = extension.postApiAction(apiReq); + Assert.assertTrue(response.isAllowed()); + } + +} diff --git a/restcomm/restcomm.extension.controller/src/test/resources/log4j.xml b/restcomm/restcomm.extension.controller/src/test/resources/log4j.xml new file mode 100644 index 0000000000..40d05b6a28 --- /dev/null +++ b/restcomm/restcomm.extension.controller/src/test/resources/log4j.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/restcomm/restcomm.fax/pom.xml b/restcomm/restcomm.fax/pom.xml index a2966ffb99..5adb5d3f4a 100644 --- a/restcomm/restcomm.fax/pom.xml +++ b/restcomm/restcomm.fax/pom.xml @@ -1,13 +1,13 @@ 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.fax - restcomm.fax + restcomm-connect.fax + restcomm-connect.fax http://maven.apache.org @@ -32,8 +32,8 @@ - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons ${project.version} diff --git a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxRequest.java b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxRequest.java similarity index 91% rename from restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxRequest.java rename to restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxRequest.java index 8531659245..caca410709 100644 --- a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxRequest.java +++ b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxRequest.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fax; +package org.restcomm.connect.fax; import java.io.File; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxResponse.java b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxResponse.java similarity index 87% rename from restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxResponse.java rename to restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxResponse.java index 5105e49cda..32795b1a92 100644 --- a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxResponse.java +++ b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxResponse.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fax; +package org.restcomm.connect.fax; import java.net.URI; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; -import org.mobicents.servlet.restcomm.patterns.StandardResponse; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.patterns.StandardResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxServiceException.java b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxServiceException.java similarity index 96% rename from restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxServiceException.java rename to restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxServiceException.java index d3bc3c1273..722d58b280 100644 --- a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/FaxServiceException.java +++ b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/FaxServiceException.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fax; +package org.restcomm.connect.fax; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/InterfaxService.java b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java similarity index 96% rename from restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/InterfaxService.java rename to restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java index 0202c33a15..0a320b3753 100644 --- a/restcomm/restcomm.fax/src/main/java/org/mobicents/servlet/restcomm/fax/InterfaxService.java +++ b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java @@ -17,17 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fax; +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.fax/src/test/java/org/mobicents/servlet/restcomm/fax/InterfaxServiceTest.java b/restcomm/restcomm.fax/src/test/java/org/restcomm/connect/fax/InterfaxServiceTest.java similarity index 98% rename from restcomm/restcomm.fax/src/test/java/org/mobicents/servlet/restcomm/fax/InterfaxServiceTest.java rename to restcomm/restcomm.fax/src/test/java/org/restcomm/connect/fax/InterfaxServiceTest.java index d945c78998..20c30854c3 100644 --- a/restcomm/restcomm.fax/src/test/java/org/mobicents/servlet/restcomm/fax/InterfaxServiceTest.java +++ b/restcomm/restcomm.fax/src/test/java/org/restcomm/connect/fax/InterfaxServiceTest.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.fax; +package org.restcomm.connect.fax; import akka.actor.Actor; import akka.actor.ActorRef; diff --git a/restcomm/restcomm.fax/src/test/resources/interfax.xml b/restcomm/restcomm.fax/src/test/resources/interfax.xml index 4b3a993c24..c8a6996f88 100644 --- a/restcomm/restcomm.fax/src/test/resources/interfax.xml +++ b/restcomm/restcomm.fax/src/test/resources/interfax.xml @@ -12,7 +12,7 @@ - + thomasquintana Delta2637 diff --git a/restcomm/restcomm.http/pom.xml b/restcomm/restcomm.http/pom.xml index a9d6332dff..3c9fcbc22c 100644 --- a/restcomm/restcomm.http/pom.xml +++ b/restcomm/restcomm.http/pom.xml @@ -2,13 +2,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.http - restcomm.http + restcomm-connect.http + restcomm-connect.http http://maven.apache.org @@ -17,16 +17,6 @@ - - org.slf4j - slf4j-api - - - - org.slf4j - slf4j-log4j12 - - org.apache.shiro shiro-core @@ -46,6 +36,12 @@ com.googlecode.libphonenumber libphonenumber + + + javax.annotation + jsr250-api + 1.0 + javax.servlet @@ -53,10 +49,20 @@ provided + + org.apache.httpcomponents + httpasyncclient + + com.sun.jersey jersey-server + + + com.sun.jersey + jersey-json + com.sun.jersey @@ -75,53 +81,91 @@ - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons ${project.version} provided - com.telestax.servlet - restcomm.dao + org.restcomm + restcomm-connect.dao ${project.version} provided - com.telestax.servlet - restcomm.provisioning.number.api + org.restcomm + restcomm-connect.provisioning.number.api ${project.version} provided - com.telestax.servlet - restcomm.asr + org.restcomm + restcomm-connect.asr ${project.version} provided - com.telestax.servlet - restcomm.tts.api + org.restcomm + restcomm-connect.tts.api ${project.version} provided - com.telestax.servlet - restcomm.sms.api + org.restcomm + restcomm-connect.sms.api ${project.version} provided - com.telestax.servlet - restcomm.telephony.api + org.restcomm + restcomm-connect.telephony.api ${project.version} provided + + + org.restcomm + restcomm-connect.identity + ${project.version} + provided + + + + org.restcomm + restcomm-connect.monitoring.service + ${project.version} + provided + + + + org.restcomm + restcomm-connect.email.api + ${project.version} + + + + org.restcomm + restcomm-connect.email + ${project.version} + + + + org.restcomm + restcomm-connect.mscontrol.api + ${project.version} + + + + org.restcomm + restcomm-connect.dns.api + ${project.version} + @@ -138,13 +182,6 @@ test - - org.mobicents.servlet.sip.containers - sip-servlets-tomcat-7 - ${sipservletapi.version} - test - - org.mobicents.servlet.sip sip-servlets-application-router @@ -185,9 +222,8 @@ - hsqldb + org.hsqldb hsqldb - test @@ -215,9 +251,37 @@ - org.cafesip.sipunit - sipunit + org.mockito + mockito-core + ${mockito-core.version} test + + + com.github.tomakehurst + wiremock + 1.57 + + standalone + test + + + org.restcomm + restcomm-connect.extension.api + ${project.version} + + + org.restcomm + restcomm-connect.extension.controller + ${project.version} + + + + com.github.java-json-tools + json-schema-validator + 2.2.8 + + diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AbstractEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AbstractEndpoint.java deleted file mode 100644 index 0bee28e107..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AbstractEndpoint.java +++ /dev/null @@ -1,121 +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.mobicents.servlet.restcomm.http; - -import java.net.URI; - -import javax.ws.rs.core.MultivaluedMap; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.SecurityUtils; -import org.apache.shiro.authz.AuthorizationException; -import org.apache.shiro.subject.Subject; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.util.StringUtils; - -import com.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author jean.deruelle@telestax.com - */ -@NotThreadSafe -public abstract class AbstractEndpoint { - private String defaultApiVersion; - protected Configuration configuration; - protected String baseRecordingsPath; - - public AbstractEndpoint() { - super(); - } - - protected void init(final Configuration configuration) { - final String path = configuration.getString("recordings-path"); - baseRecordingsPath = StringUtils.addSuffixIfNotPresent(path, "/"); - defaultApiVersion = configuration.getString("api-version"); - } - - protected String getApiVersion(final MultivaluedMap data) { - String apiVersion = defaultApiVersion; - if (data != null && data.containsKey("ApiVersion")) { - apiVersion = data.getFirst("ApiVersion"); - } - return apiVersion; - } - - protected PhoneNumber getPhoneNumber(final MultivaluedMap data) { - final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); - PhoneNumber phoneNumber = null; - try { - phoneNumber = phoneNumberUtil.parse(data.getFirst("PhoneNumber"), "US"); - } catch (final NumberParseException ignored) { - } - return phoneNumber; - } - - protected String getMethod(final String name, final MultivaluedMap data) { - String method = "POST"; - if (data.containsKey(name)) { - method = data.getFirst(name); - } - return method; - } - - protected Sid getSid(final String name, final MultivaluedMap data) { - Sid sid = null; - if (data.containsKey(name)) { - sid = new Sid(data.getFirst(name)); - } - return sid; - } - - protected URI getUrl(final String name, final MultivaluedMap data) { - URI uri = null; - if (data.containsKey(name)) { - uri = URI.create(data.getFirst(name)); - } - return uri; - } - - protected boolean getHasVoiceCallerIdLookup(final MultivaluedMap data) { - boolean hasVoiceCallerIdLookup = false; - if (data.containsKey("VoiceCallerIdLookup")) { - final String value = data.getFirst("VoiceCallerIdLookup"); - if ("true".equalsIgnoreCase(value)) { - return true; - } - } - return hasVoiceCallerIdLookup; - } - - protected void secure(final Account account, final String permission) throws AuthorizationException { - final Subject subject = SecurityUtils.getSubject(); - final Sid accountSid = account.getSid(); - if (account.getStatus().equals(Account.Status.ACTIVE) && (subject.hasRole("Administrator") || (subject.getPrincipal().equals(accountSid) && subject.isPermitted(permission)))) { - return; - } else { - throw new AuthorizationException(); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsEndpoint.java deleted file mode 100644 index 71dc3e1db1..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsEndpoint.java +++ /dev/null @@ -1,302 +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.mobicents.servlet.restcomm.http; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.MediaType; - -import static javax.ws.rs.core.MediaType.*; - -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.SecurityUtils; -import org.apache.shiro.authz.AuthorizationException; -import org.apache.shiro.crypto.hash.Md5Hash; -import org.apache.shiro.subject.Subject; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.AccountList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.AccountConverter; -import org.mobicents.servlet.restcomm.http.converter.AccountListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.util.StringUtils; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public abstract class AccountsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected AccountsDao dao; - protected Gson gson; - protected XStream xstream; - - public AccountsEndpoint() { - super(); - } - - @PostConstruct - private void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - dao = storage.getAccountsDao(); - final AccountConverter converter = new AccountConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Account.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new AccountListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - private Account createFrom(final Sid accountSid, final MultivaluedMap data) { - validate(data); - - final DateTime now = DateTime.now(); - final String emailAddress = data.getFirst("EmailAddress"); - - // Issue 108: https://bitbucket.org/telestax/telscale-restcomm/issue/108/account-sid-could-be-a-hash-of-the - final Sid sid = Sid.generate(Sid.Type.ACCOUNT, emailAddress); - - String friendlyName = emailAddress; - if (data.containsKey("FriendlyName")) { - friendlyName = data.getFirst("FriendlyName"); - } - final Account.Type type = Account.Type.FULL; - Account.Status status = Account.Status.ACTIVE; - if (data.containsKey("Status")) { - status = Account.Status.valueOf(data.getFirst("Status")); - } - final String password = data.getFirst("Password"); - final String authToken = new Md5Hash(password).toString(); - final String role = data.getFirst("Role"); - String rootUri = configuration.getString("root-uri"); - rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); - final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(getApiVersion(null)).append("/Accounts/").append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - return new Account(sid, now, now, emailAddress, friendlyName, accountSid, type, status, authToken, role, uri); - } - - protected Response getAccount(final String accountSid, final MediaType responseType) { - - Sid sid = null; - Account account = null; - if (Sid.pattern.matcher(accountSid).matches()) { - try { - sid = new Sid(accountSid); - account = dao.getAccount(sid); - } catch (Exception e) { - return status(NOT_FOUND).build(); - } - - } else { - try { - account = dao.getAccount(accountSid); - sid = account.getSid(); - } catch (Exception e) { - return status(NOT_FOUND).build(); - } - } - - try { - final Subject subject = SecurityUtils.getSubject(); - if (subject.hasRole("Administrator") - || (subject.getPrincipal().equals(accountSid) && subject.isPermitted("RestComm:Modify:Accounts"))) {} - else {return status(UNAUTHORIZED).build();} - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - - if (account == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(account); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(account), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - protected Response deleteAccount(final String sid) { - final Subject subject = SecurityUtils.getSubject(); - final Sid accountSid = new Sid((String) subject.getPrincipal()); - final Sid sidToBeRemoved = new Sid(sid); - - try { - Account account = dao.getAccount(sidToBeRemoved); - secure(account, "RestComm:Delete:Accounts"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - // Prevent removal of Administrator account - if (sid.equalsIgnoreCase(accountSid.toString())) - return status(BAD_REQUEST).build(); - - if (dao.getAccount(sidToBeRemoved) == null) - return status(NOT_FOUND).build(); - - dao.removeAccount(sidToBeRemoved); - return ok().build(); - } - - protected Response getAccounts(final MediaType responseType) { - final Subject subject = SecurityUtils.getSubject(); - final Sid sid = new Sid((String) subject.getPrincipal()); - try { - Account account = dao.getAccount(sid); - secure(account, "RestComm:Read:Accounts"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Account account = dao.getAccount(sid); - if (account == null) { - return status(NOT_FOUND).build(); - } else { - final List accounts = new ArrayList(); - accounts.add(account); - accounts.addAll(dao.getAccounts(sid)); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new AccountList(accounts)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(accounts), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - protected Response putAccount(final MultivaluedMap data, final MediaType responseType) { - final Subject subject = SecurityUtils.getSubject(); - final Sid sid = new Sid((String) subject.getPrincipal()); - Account account = null; - try { - account = createFrom(sid, data); - } catch (final NullPointerException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - - // If Account already exists don't add it again - if (dao.getAccount(account.getSid()) == null) { - final Account parent = dao.getAccount(sid); - if (parent.getStatus().equals(Account.Status.ACTIVE) && (subject.hasRole("Administrator") || (subject.isPermitted("RestComm:Create:Accounts")))) { - if (!subject.hasRole("Administrator") || !data.containsKey("Role")) { - account = account.setRole(parent.getRole()); - } - dao.addAccount(account); - } else { - return status(UNAUTHORIZED).build(); - } - } - - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(account), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(account); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - - private Account update(final Account account, final MultivaluedMap data) { - Account result = account; - if (data.containsKey("FriendlyName")) { - result = result.setFriendlyName(data.getFirst("FriendlyName")); - } - if (data.containsKey("Status")) { - result = result.setStatus(Account.Status.getValueOf(data.getFirst("Status"))); - } else { - result = result.setStatus(Account.Status.ACTIVE); - } - if (data.containsKey("Password")) { - final String hash = new Md5Hash(data.getFirst("Password")).toString(); - result = result.setAuthToken(hash); - } - if (data.containsKey("Auth_Token")) { - result = result.setAuthToken(data.getFirst("Auth_Token")); - } - return result; - } - - protected Response updateAccount(final String accountSid, final MultivaluedMap data, - final MediaType responseType) { - final Sid sid = new Sid(accountSid); - Account account = dao.getAccount(sid); - if (account == null) { - return status(NOT_FOUND).build(); - } else { - account = update(account, data); - final Subject subject = SecurityUtils.getSubject(); - if (subject.hasRole("Administrator") - || (subject.getPrincipal().equals(accountSid) && subject.isPermitted("RestComm:Modify:Accounts"))) { - dao.updateAccount(account); - } else { - return status(UNAUTHORIZED).build(); - } - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(account), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(account); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - private void validate(final MultivaluedMap data) throws NullPointerException { - if (!data.containsKey("EmailAddress")) { - throw new NullPointerException("Email address can not be null."); - } else if (!data.containsKey("Password")) { - throw new NullPointerException("Password can not be null."); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsJsonEndpoint.java deleted file mode 100644 index 4cefed0c8d..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsJsonEndpoint.java +++ /dev/null @@ -1,68 +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.mobicents.servlet.restcomm.http; - -import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Accounts.json") -@ThreadSafe -public final class AccountsJsonEndpoint extends AccountsEndpoint { - public AccountsJsonEndpoint() { - super(); - } - - @Path("/{accountSid}") - @GET - public Response getAccountAsJson(@PathParam("accountSid") final String accountSid) { - return getAccount(accountSid, APPLICATION_JSON_TYPE); - } - - @GET - public Response getAccounts() { - return getAccounts(APPLICATION_JSON_TYPE); - } - - @Path("/{sid}.json") - @DELETE - public Response deleteAccountAsJson(@PathParam("sid") final String sid) { - return deleteAccount(sid); - } - - @Consumes(APPLICATION_FORM_URLENCODED) - @POST - public Response putAccount(final MultivaluedMap data) { - return putAccount(data, APPLICATION_JSON_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsXmlEndpoint.java deleted file mode 100644 index ab330fc0b2..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AccountsXmlEndpoint.java +++ /dev/null @@ -1,102 +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.mobicents.servlet.restcomm.http; - -import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; -import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Accounts") -@ThreadSafe -public final class AccountsXmlEndpoint extends AccountsEndpoint { - public AccountsXmlEndpoint() { - super(); - } - - @Path("/{sid}") - @DELETE - public Response deleteAccountAsXml(@PathParam("sid") final String sid) { - return deleteAccount(sid); - } - - @Path("/{accountSid}") - @GET - public Response getAccountAsXml(@PathParam("accountSid") final String accountSid) { - return getAccount(accountSid, APPLICATION_XML_TYPE); - } - - @GET - public Response getAccounts() { - return getAccounts(APPLICATION_XML_TYPE); - } - - @Consumes(APPLICATION_FORM_URLENCODED) - @POST - public Response putAccount(final MultivaluedMap data) { - return putAccount(data, APPLICATION_XML_TYPE); - } - - @Path("/{accountSid}.json") - @Consumes(APPLICATION_FORM_URLENCODED) - @POST - public Response updateAccountAsJsonPost(@PathParam("accountSid") final String accountSid, - final MultivaluedMap data) { - return updateAccount(accountSid, data, APPLICATION_JSON_TYPE); - } - - @Path("/{accountSid}.json") - @Consumes(APPLICATION_FORM_URLENCODED) - @PUT - public Response updateAccountAsJsonPut(@PathParam("accountSid") final String accountSid, - final MultivaluedMap data) { - return updateAccount(accountSid, data, APPLICATION_JSON_TYPE); - } - - @Path("/{accountSid}") - @Consumes(APPLICATION_FORM_URLENCODED) - @POST - public Response updateAccountAsXmlPost(@PathParam("accountSid") final String accountSid, - final MultivaluedMap data) { - return updateAccount(accountSid, data, APPLICATION_XML_TYPE); - } - - @Path("/{accountSid}") - @Consumes(APPLICATION_FORM_URLENCODED) - @PUT - public Response updateAccountAsXmlPut(@PathParam("accountSid") final String accountSid, - final MultivaluedMap data) { - return updateAccount(accountSid, data, APPLICATION_XML_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsEndpoint.java deleted file mode 100644 index cc594e4378..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsEndpoint.java +++ /dev/null @@ -1,457 +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.mobicents.servlet.restcomm.http; - -import static akka.pattern.Patterns.ask; -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.ok; -import static javax.ws.rs.core.Response.status; -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static javax.ws.rs.core.Response.Status.NOT_FOUND; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; - -import java.net.URI; -import java.net.URL; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -//import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordFilter; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.CallDetailRecordConverter; -import org.mobicents.servlet.restcomm.http.converter.CallDetailRecordListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallManagerResponse; -import org.mobicents.servlet.restcomm.telephony.CallResponse; -import org.mobicents.servlet.restcomm.telephony.CreateCall; -import org.mobicents.servlet.restcomm.telephony.ExecuteCallScript; -import org.mobicents.servlet.restcomm.telephony.GetCall; -import org.mobicents.servlet.restcomm.telephony.GetCallInfo; -import org.mobicents.servlet.restcomm.telephony.Hangup; -import org.mobicents.servlet.restcomm.telephony.UpdateCallScript; - -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.Duration; -import akka.actor.ActorRef; -import akka.util.Timeout; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.thoughtworks.xstream.XStream; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author gvagenas@gmail.com (George Vagenas) - */ -@NotThreadSafe -public abstract class CallsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - private ActorRef callManager; - private DaoManager daos; - private Gson gson; - private GsonBuilder builder; - private XStream xstream; - private CallDetailRecordListConverter listConverter; - - private boolean normalizePhoneNumbers; - - public CallsEndpoint() { - super(); - } - - @PostConstruct - public void init() { - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - callManager = (ActorRef) context.getAttribute("org.mobicents.servlet.restcomm.telephony.CallManager"); - daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); - super.init(configuration); - CallDetailRecordConverter converter = new CallDetailRecordConverter(configuration); - listConverter = new CallDetailRecordListConverter(configuration); - builder = new GsonBuilder(); - builder.registerTypeAdapter(CallDetailRecord.class, converter); - builder.registerTypeAdapter(CallDetailRecordList.class, listConverter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - xstream.registerConverter(listConverter); - - normalizePhoneNumbers = configuration.getBoolean("normalize-numbers-for-outbound-calls"); - } - - protected Response getCall(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Read:Calls"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); - final CallDetailRecord cdr = dao.getCallDetailRecord(new Sid(sid)); - if (cdr == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(cdr); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(cdr), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - // Issue 153: https://bitbucket.org/telestax/telscale-restcomm/issue/153 - // Issue 110: https://bitbucket.org/telestax/telscale-restcomm/issue/110 - protected Response getCalls(final String accountSid, UriInfo info, MediaType responseType) { - - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Read:Calls"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - - String pageSize = info.getQueryParameters().getFirst("PageSize"); - String page = info.getQueryParameters().getFirst("Page"); - // String afterSid = info.getQueryParameters().getFirst("AfterSid"); - String recipient = info.getQueryParameters().getFirst("To"); - String sender = info.getQueryParameters().getFirst("From"); - String status = info.getQueryParameters().getFirst("Status"); - String startTime = info.getQueryParameters().getFirst("StartTime"); - String parentCallSid = info.getQueryParameters().getFirst("ParentCallSid"); - - if (pageSize == null) { - pageSize = "50"; - } - - if (page == null) { - page = "0"; - } - - int limit = Integer.parseInt(pageSize); - int offset = (page == "0") ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer - .parseInt(pageSize)); - - CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); - - CallDetailRecordFilter filterForTotal = new CallDetailRecordFilter(accountSid, recipient, sender, status, startTime, - parentCallSid, null, null); - final int total = dao.getTotalCallDetailRecords(filterForTotal); - - if (Integer.parseInt(page) > (total / limit)) { - return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); - } - - CallDetailRecordFilter filter = new CallDetailRecordFilter(accountSid, recipient, sender, status, startTime, - parentCallSid, limit, offset); - - final List cdrs = dao.getCallDetailRecords(filter); - - listConverter.setCount(total); - listConverter.setPage(Integer.parseInt(page)); - listConverter.setPageSize(Integer.parseInt(pageSize)); - listConverter.setPathUri(info.getRequestUri().getPath()); - - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new CallDetailRecordList(cdrs)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(new CallDetailRecordList(cdrs)), APPLICATION_JSON).build(); - } else { - return null; - } - } - - private void normalize(final MultivaluedMap data) throws IllegalArgumentException { - final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); - final String from = data.getFirst("From"); - data.remove("From"); - try { - data.putSingle("From", phoneNumberUtil.format(phoneNumberUtil.parse(from, "US"), PhoneNumberFormat.E164)); - } catch (final NumberParseException exception) { - throw new IllegalArgumentException(exception); - } - final String to = data.getFirst("To"); - // Only try to normalize phone numbers. - if (to.startsWith("client")) { - if (to.split(":").length != 2) { - throw new IllegalArgumentException(to + " is an invalid client identifier."); - } - } else if (!to.contains("@")) { - data.remove("To"); - try { - data.putSingle("To", phoneNumberUtil.format(phoneNumberUtil.parse(to, "US"), PhoneNumberFormat.E164)); - } catch (final NumberParseException exception) { - throw new IllegalArgumentException(exception); - } - } - URI.create(data.getFirst("Url")); - } - - @SuppressWarnings("unchecked") - protected Response putCall(final String accountSid, final MultivaluedMap data, final MediaType responseType) { - final Sid accountId = new Sid(accountSid); - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Create:Calls"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - try { - validate(data); - if (normalizePhoneNumbers) - normalize(data); - } catch (final RuntimeException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - final String from = data.getFirst("From"); - final String to = data.getFirst("To"); - final String username = data.getFirst("Username"); - final String password = data.getFirst("Password"); - final Integer timeout = getTimeout(data); - final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); - CreateCall create = null; - try { - if (to.contains("@")) { - create = new CreateCall(from, to, username, password, true, timeout != null ? timeout : 30, CreateCall.Type.SIP, - accountId); - } else if (to.startsWith("client")) { - create = new CreateCall(from, to, username, password, true, timeout != null ? timeout : 30, CreateCall.Type.CLIENT, - accountId); - } else { - create = new CreateCall(from, to, username, password, true, timeout != null ? timeout : 30, CreateCall.Type.PSTN, - accountId); - } - create.setCreateCDR(false); - Future future = (Future) ask(callManager, create, expires); - Object object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); - Class klass = object.getClass(); - if (CallManagerResponse.class.equals(klass)) { - final CallManagerResponse managerResponse = (CallManagerResponse) object; - if (managerResponse.succeeded()) { - final ActorRef call = managerResponse.get(); - future = (Future) ask(call, new GetCallInfo(), expires); - object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); - klass = object.getClass(); - if (CallResponse.class.equals(klass)) { - final CallResponse callResponse = (CallResponse) object; - if (callResponse.succeeded()) { - final CallInfo callInfo = callResponse.get(); - // Execute the call script. - final String version = getApiVersion(data); - final URI url = getUrl("Url", data); - final String method = getMethod("Method", data); - final URI fallbackUrl = getUrl("FallbackUrl", data); - final String fallbackMethod = getMethod("FallbackMethod", data); - final URI callback = getUrl("StatusCallback", data); - final String callbackMethod = getMethod("StatusCallbackMethod", data); - final ExecuteCallScript execute = new ExecuteCallScript(call, accountId, version, url, method, - fallbackUrl, fallbackMethod, callback, callbackMethod); - callManager.tell(execute, null); - // Create a call detail record for the call. -// final CallDetailRecord.Builder builder = CallDetailRecord.builder(); -// builder.setSid(callInfo.sid()); -// builder.setDateCreated(callInfo.dateCreated()); -// builder.setAccountSid(accountId); -// builder.setTo(to); -// builder.setCallerName(callInfo.fromName()); -// builder.setFrom(from); -// builder.setForwardedFrom(callInfo.forwardedFrom()); -// builder.setStatus(callInfo.state().toString()); -// final DateTime now = DateTime.now(); -// builder.setStartTime(now); -// builder.setDirection(callInfo.direction()); -// builder.setApiVersion(version); -// final StringBuilder buffer = new StringBuilder(); -// buffer.append("/").append(version).append("/Accounts/"); -// buffer.append(accountId.toString()).append("/Calls/"); -// buffer.append(callInfo.sid().toString()); -// final URI uri = URI.create(buffer.toString()); -// builder.setUri(uri); - - CallDetailRecord cdr = daos.getCallDetailRecordsDao().getCallDetailRecord(callInfo.sid()); -// -// builder.setCallPath(call.path().toString()); -// -// final CallDetailRecord cdr = builder.build(); -// daos.getCallDetailRecordsDao().addCallDetailRecord(cdr); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(cdr), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - return ok(xstream.toXML(new RestCommResponse(cdr)), APPLICATION_XML).build(); - } else { - return null; - } - } - } - } else { - return status(INTERNAL_SERVER_ERROR).entity(managerResponse.cause() + " : " +managerResponse.error()).build(); - } - } - return status(INTERNAL_SERVER_ERROR).build(); - } catch (final Exception exception) { - return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); - } - } - - // Issue 139: https://bitbucket.org/telestax/telscale-restcomm/issue/139 - @SuppressWarnings("unchecked") - protected Response updateCall(final String sid, final String callSid, final MultivaluedMap data, - final MediaType responseType) { - final Sid accountSid = new Sid(sid); - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Modify:Calls"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - - final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); - - final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); - final CallDetailRecord cdr = dao.getCallDetailRecord(new Sid(callSid)); - - String callPath = null; - final ActorRef call; - final CallInfo callInfo; - - try { - callPath = cdr.getCallPath(); - Future future = (Future) ask(callManager, new GetCall(callPath), expires); - call = (ActorRef) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); - - future = (Future) ask(call, new GetCallInfo(), expires); - CallResponse response = (CallResponse) Await.result(future, - Duration.create(10, TimeUnit.SECONDS)); - callInfo = response.get(); - } catch (Exception exception) { - return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); - } - - final String url = data.getFirst("Url"); - String method = data.getFirst("Method"); - final String status = data.getFirst("Status"); - final String fallBackUrl = data.getFirst("FallbackUrl"); - String fallBackMethod = data.getFirst("FallbackMethod"); - final String statusCallBack = data.getFirst("StatusCallback"); - String statusCallbackMethod = data.getFirst("StatusCallbackMethod"); - - if (method == null) - method = "POST"; - - if (url != null && status != null) { - // Throw exception. We can either redirect a running call using Url or change the state of a Call with Status - final String errorMessage = "You can either redirect a running call using \"Url\" or change the state of a Call with \"Status\""; - return status(javax.ws.rs.core.Response.Status.CONFLICT).entity(errorMessage).build(); - } - - // Modify state of a call - if (status != null) { - if (status.equalsIgnoreCase("canceled")) { - if (callInfo.state().name().equalsIgnoreCase("queued") || callInfo.state().name().equalsIgnoreCase("ringing")) { - if (call != null) { - call.tell(new Hangup(), null); - } - } else { - // Do Nothing. We can only cancel Queued or Ringing calls - } - } - - if (status.equalsIgnoreCase("completed")) { - // Specifying "completed" will attempt to hang up a call even if it's already in progress. - if (call != null) { - call.tell(new Hangup(), null); - } - } - } - - if (url != null && call != null) { - try { - final String version = getApiVersion(data); - final URI uri = (new URL(url)).toURI(); - - URI fallbackUri = (fallBackUrl != null) ? (new URL(fallBackUrl)).toURI() : null; - fallBackMethod = (fallBackMethod == null) ? "POST" : fallBackMethod; - URI callbackUri = (statusCallBack != null) ? (new URL(statusCallBack)).toURI() : null; - statusCallbackMethod = (statusCallbackMethod == null) ? "POST" : statusCallbackMethod; - - final UpdateCallScript update = new UpdateCallScript(call, accountSid, version, uri, method, fallbackUri, - fallBackMethod, callbackUri, statusCallbackMethod); - callManager.tell(update, null); - } catch (Exception exception) { - return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); - } - } - - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(cdr), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - return ok(xstream.toXML(new RestCommResponse(cdr)), APPLICATION_XML).build(); - } else { - return null; - } - } - - private Integer getTimeout(final MultivaluedMap data) { - Integer result = 60; - if (data.containsKey("Timeout")) { - result = Integer.parseInt(data.getFirst("Timeout")); - } - return result; - } - - private void validate(final MultivaluedMap data) throws NullPointerException { - if (!data.containsKey("From")) { - throw new NullPointerException("From can not be null."); - } else if (!data.containsKey("To")) { - throw new NullPointerException("To can not be null."); - } else if (!data.containsKey("Url")) { - throw new NullPointerException("Url can not be null."); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsEndpoint.java deleted file mode 100644 index 4c6a1b5a46..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsEndpoint.java +++ /dev/null @@ -1,262 +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.mobicents.servlet.restcomm.http; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import java.net.URI; -import java.util.List; - -import static javax.ws.rs.core.MediaType.*; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.ClientsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Client; -import org.mobicents.servlet.restcomm.entities.ClientList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.ClientConverter; -import org.mobicents.servlet.restcomm.http.converter.ClientListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.util.StringUtils; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class ClientsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected ClientsDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - public ClientsEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - dao = storage.getClientsDao(); - accountsDao = storage.getAccountsDao(); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - final ClientConverter converter = new ClientConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Client.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new ClientListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - private Client createFrom(final Sid accountSid, final MultivaluedMap data) { - final Client.Builder builder = Client.builder(); - final Sid sid = Sid.generate(Sid.Type.CLIENT); - builder.setSid(sid); - builder.setApiVersion(getApiVersion(data)); - builder.setFriendlyName(getFriendlyName(data.getFirst("Login"), data)); - builder.setAccountSid(accountSid); - builder.setLogin(data.getFirst("Login")); - builder.setPassword(data.getFirst("Password")); - builder.setStatus(getStatus(data)); - builder.setVoiceUrl(getUrl("VoiceUrl", data)); - builder.setVoiceMethod(getMethod("VoiceMethod", data)); - builder.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); - builder.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); - builder.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); - String rootUri = configuration.getString("root-uri"); - rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); - final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) - .append("/Clients/").append(sid.toString()); - builder.setUri(URI.create(buffer.toString())); - return builder.build(); - } - - protected Response getClient(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Clients"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Client client = dao.getClient(new Sid(sid)); - if (client == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(client); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(client), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - protected Response getClients(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Clients"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List clients = dao.getClients(new Sid(accountSid)); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new ClientList(clients)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(clients), APPLICATION_JSON).build(); - } else { - return null; - } - } - - private String getFriendlyName(final String login, final MultivaluedMap data) { - String friendlyName = login; - if (data.containsKey("FriendlyName")) { - friendlyName = data.getFirst("FriendlyName"); - } - return friendlyName; - } - - private int getStatus(final MultivaluedMap data) { - int status = Client.ENABLED; - if (data.containsKey("Status")) { - try { - status = Integer.parseInt(data.getFirst("Status")); - } catch (final NumberFormatException ignored) { - } - } - return status; - } - - public Response putClient(final String accountSid, final MultivaluedMap data, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Create:Clients"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - try { - validate(data); - } catch (final NullPointerException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - - // Issue 109: https://bitbucket.org/telestax/telscale-restcomm/issue/109 - Client client = dao.getClient(data.getFirst("Login")); - if (client == null) { - client = createFrom(new Sid(accountSid), data); - dao.addClient(client); - } - - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(client); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(client), APPLICATION_JSON).build(); - } else { - return null; - } - } - - protected Response updateClient(final String accountSid, final String sid, final MultivaluedMap data, - final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Modify:Clients"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Client client = dao.getClient(new Sid(sid)); - if (client == null) { - return status(NOT_FOUND).build(); - } else { - dao.updateClient(update(client, data)); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(client); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(client), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - private void validate(final MultivaluedMap data) throws RuntimeException { - if (!data.containsKey("Login")) { - throw new NullPointerException("Login can not be null."); - } else if (!data.containsKey("Password")) { - throw new NullPointerException("Password can not be null."); - } - } - - private Client update(final Client client, final MultivaluedMap data) { - Client result = client; - if (data.containsKey("FriendlyName")) { - result = result.setFriendlyName(data.getFirst("FriendlyName")); - } - if (data.containsKey("Password")) { - result = result.setPassword(data.getFirst("Password")); - } - if (data.containsKey("Status")) { - result = result.setStatus(getStatus(data)); - } - if (data.containsKey("VoiceUrl")) { - result = result.setVoiceUrl(getUrl("VoiceUrl", data)); - } - if (data.containsKey("VoiceMethod")) { - result = result.setVoiceMethod(getMethod("VoiceMethod", data)); - } - if (data.containsKey("VoiceFallbackUrl")) { - result = result.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); - } - if (data.containsKey("VoiceFallbackMethod")) { - result = result.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); - } - if (data.containsKey("VoiceApplicationSid")) { - result = result.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); - } - return result; - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesEndpoint.java deleted file mode 100644 index f525451ba6..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesEndpoint.java +++ /dev/null @@ -1,38 +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.mobicents.servlet.restcomm.http; - -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; - -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class ConferencesEndpoint extends AbstractEndpoint { - @Context - private ServletContext context; - - public ConferencesEndpoint() { - super(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesJsonEndpoint.java deleted file mode 100644 index 6818fcb842..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesJsonEndpoint.java +++ /dev/null @@ -1,32 +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.mobicents.servlet.restcomm.http; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class ConferencesJsonEndpoint extends ConferencesEndpoint { - public ConferencesJsonEndpoint() { - super(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesXmlEndpoint.java deleted file mode 100644 index f739efcd66..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ConferencesXmlEndpoint.java +++ /dev/null @@ -1,32 +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.mobicents.servlet.restcomm.http; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class ConferencesXmlEndpoint extends ConferencesEndpoint { - public ConferencesXmlEndpoint() { - super(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysEndpoint.java deleted file mode 100644 index cc47e1ec95..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysEndpoint.java +++ /dev/null @@ -1,216 +0,0 @@ -package org.mobicents.servlet.restcomm.http; - -import java.net.URI; -import java.util.List; - -import static javax.ws.rs.core.MediaType.*; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.GatewaysDao; -import org.mobicents.servlet.restcomm.entities.Gateway; -import org.mobicents.servlet.restcomm.entities.GatewayList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.GatewayConverter; -import org.mobicents.servlet.restcomm.http.converter.GatewayListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.util.StringUtils; - -@ThreadSafe -public class GatewaysEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected GatewaysDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - public GatewaysEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - dao = storage.getGatewaysDao(); - accountsDao = storage.getAccountsDao(); - final GatewayConverter converter = new GatewayConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Gateway.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new GatewayListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - private Gateway createFrom(final MultivaluedMap data) { - final Gateway.Builder builder = Gateway.builder(); - final Sid sid = Sid.generate(Sid.Type.GATEWAY); - builder.setSid(sid); - String friendlyName = data.getFirst("FriendlyName"); - if (friendlyName == null || friendlyName.isEmpty()) { - friendlyName = data.getFirst("UserName"); - } - builder.setFriendlyName(friendlyName); - builder.setPassword(data.getFirst("Password")); - builder.setProxy(data.getFirst("Proxy")); - final boolean register = Boolean.parseBoolean(data.getFirst("Register")); - builder.setRegister(register); - builder.setUserName(data.getFirst("UserName")); - final int ttl = Integer.parseInt(data.getFirst("TTL")); - builder.setTimeToLive(ttl); - String rootUri = configuration.getString("root-uri"); - rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); - final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(getApiVersion(data)).append("/Management/").append("Gateways/").append(sid.toString()); - builder.setUri(URI.create(buffer.toString())); - return builder.build(); - } - - protected Response getGateway(final String sid, final MediaType responseType) { - final Sid accountSid = Sid.generate(Sid.Type.INVALID); - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Gateways"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Gateway gateway = dao.getGateway(new Sid(sid)); - if (gateway == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(gateway); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(gateway), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - protected Response getGateways(final MediaType responseType) { - final Sid accountSid = Sid.generate(Sid.Type.INVALID); - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Gateways"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List gateways = dao.getGateways(); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new GatewayList(gateways)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(gateways), APPLICATION_JSON).build(); - } else { - return null; - } - } - - protected Response putGateway(final MultivaluedMap data, final MediaType responseType) { - final Sid accountSid = Sid.generate(Sid.Type.INVALID); - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Create:Gateways"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - try { - validate(data); - } catch (final RuntimeException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - final Gateway gateway = createFrom(data); - dao.addGateway(gateway); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(gateway); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(gateway), APPLICATION_JSON).build(); - } else { - return null; - } - } - - protected Response updateGateway(final String sid, final MultivaluedMap data, final MediaType responseType) { - final Sid accountSid = Sid.generate(Sid.Type.INVALID); - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Modify:Gateways"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Gateway gateway = dao.getGateway(new Sid(sid)); - if (gateway == null) { - return status(NOT_FOUND).build(); - } else { - dao.updateGateway(update(gateway, data)); - if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(gateway); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(gateway), APPLICATION_JSON).build(); - } else { - return null; - } - } - } - - private void validate(final MultivaluedMap data) { - if (!data.containsKey("UserName")) { - throw new NullPointerException("UserName can not be null."); - } else if (!data.containsKey("Password")) { - throw new NullPointerException("Password can not be null."); - } else if (!data.containsKey("Proxy")) { - throw new NullPointerException("The Proxy can not be null"); - } else if (!data.containsKey("Register")) { - throw new NullPointerException("Register must be true or false"); - } - } - - private Gateway update(final Gateway gateway, final MultivaluedMap data) { - Gateway result = gateway; - if (data.containsKey("FriendlyName")) { - result = result.setFriendlyName(data.getFirst("FriendlyName")); - } - if (data.containsKey("UserName")) { - result = result.setUserName(data.getFirst("UserName")); - } - if (data.containsKey("Password")) { - result = result.setPassword(data.getFirst("Password")); - } - if (data.containsKey("Proxy")) { - result = result.setProxy(data.getFirst("Proxy")); - } - if (data.containsKey("Register")) { - result = result.setRegister(Boolean.parseBoolean("Register")); - } - if (data.containsKey("TTL")) { - result = result.setTimeToLive(Integer.parseInt(data.getFirst("TTL"))); - } - return result; - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysJsonEndpoint.java deleted file mode 100644 index 8bd902e094..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysJsonEndpoint.java +++ /dev/null @@ -1,51 +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.mobicents.servlet.restcomm.http; - -import static javax.ws.rs.core.MediaType.*; - -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Management/Gateways.json") -@ThreadSafe -public class GatewaysJsonEndpoint extends GatewaysEndpoint { - public GatewaysJsonEndpoint() { - super(); - } - - @GET - public Response getClients() { - return getGateways(APPLICATION_JSON_TYPE); - } - - @POST - public Response putClient(final MultivaluedMap data) { - return putGateway(data, APPLICATION_JSON_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysXmlEndpoint.java deleted file mode 100644 index f8c8987a41..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/GatewaysXmlEndpoint.java +++ /dev/null @@ -1,117 +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.mobicents.servlet.restcomm.http; - -import static javax.ws.rs.core.MediaType.*; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Management/Gateways") -@ThreadSafe -public final class GatewaysXmlEndpoint extends GatewaysEndpoint { - public GatewaysXmlEndpoint() { - super(); - } - - private Response deleteGateway(final String sid) { - final Sid accountSid = Sid.generate(Sid.Type.INVALID); - try { - secure(super.accountsDao.getAccount(accountSid), "RestComm:Modify:Gateways"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - dao.removeGateway(new Sid(sid)); - return ok().build(); - } - - @Path("/{sid}.json") - @DELETE - public Response deleteGatewayAsJson(@PathParam("sid") final String sid) { - return deleteGateway(sid); - } - - @Path("/{sid}") - @DELETE - public Response deleteGatewayAsXml(@PathParam("sid") final String sid) { - return deleteGateway(sid); - } - - @Path("/{sid}.json") - @GET - public Response getGatewayAsJson(@PathParam("sid") final String sid) { - return getGateway(sid, APPLICATION_JSON_TYPE); - } - - @Path("/{sid}") - @GET - public Response getGatewayAsXml(@PathParam("sid") final String sid) { - return getGateway(sid, APPLICATION_XML_TYPE); - } - - @GET - public Response getGateways() { - return getGateways(APPLICATION_XML_TYPE); - } - - @POST - public Response putGateway(final MultivaluedMap data) { - return putGateway(data, APPLICATION_XML_TYPE); - } - - @Path("/{sid}.json") - @POST - public Response updateGatewayAsJsonPost(@PathParam("sid") final String sid, final MultivaluedMap data) { - return updateGateway(sid, data, APPLICATION_JSON_TYPE); - } - - @Path("/{sid}.json") - @PUT - public Response updateGatewayAsJsonPut(@PathParam("sid") final String sid, final MultivaluedMap data) { - return updateGateway(sid, data, APPLICATION_JSON_TYPE); - } - - @Path("/{sid}") - @POST - public Response updateGatewayAsXmlPost(@PathParam("sid") final String sid, final MultivaluedMap data) { - return updateGateway(sid, data, APPLICATION_XML_TYPE); - } - - @Path("/{sid}") - @PUT - public Response updateGatewayAsXmlPut(@PathParam("sid") final String sid, final MultivaluedMap data) { - return updateGateway(sid, data, APPLICATION_XML_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersEndpoint.java deleted file mode 100644 index 35e32da875..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersEndpoint.java +++ /dev/null @@ -1,431 +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.mobicents.servlet.restcomm.http; - -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.noContent; -import static javax.ws.rs.core.Response.ok; -import static javax.ws.rs.core.Response.status; -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.NOT_FOUND; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.servlet.sip.SipServlet; -import javax.servlet.sip.SipURI; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.IncomingPhoneNumbersDao; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumberFilter; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumberList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.AvailableCountriesConverter; -import org.mobicents.servlet.restcomm.http.converter.AvailableCountriesList; -import org.mobicents.servlet.restcomm.http.converter.IncomingPhoneNumberConverter; -import org.mobicents.servlet.restcomm.http.converter.IncomingPhoneNumberListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.loader.ObjectFactory; -import org.mobicents.servlet.restcomm.loader.ObjectInstantiationException; -import org.mobicents.servlet.restcomm.provisioning.number.api.ContainerConfiguration; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberParameters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberProvisioningManager; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; -import org.mobicents.servlet.restcomm.util.StringUtils; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; -import com.thoughtworks.xstream.XStream; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author gvagenas@gmail.com - * @author jean.deruelle@telestax.com - */ -@NotThreadSafe -public abstract class IncomingPhoneNumbersEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected PhoneNumberProvisioningManager phoneNumberProvisioningManager; - PhoneNumberParameters phoneNumberParameters; - private IncomingPhoneNumbersDao dao; - protected AccountsDao accountsDao; - private XStream xstream; - protected Gson gson; - - public IncomingPhoneNumbersEndpoint() { - super(); - } - - @PostConstruct - public void init() throws ObjectInstantiationException { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - super.init(configuration.subset("runtime-settings")); - dao = storage.getIncomingPhoneNumbersDao(); - accountsDao = storage.getAccountsDao(); - - phoneNumberProvisioningManager = (PhoneNumberProvisioningManager) context.getAttribute("PhoneNumberProvisioningManager"); - if(phoneNumberProvisioningManager == null) { - final String phoneNumberProvisioningManagerClass = configuration.getString("phone-number-provisioning[@class]"); - Configuration phoneNumberProvisioningConfiguration = configuration.subset("phone-number-provisioning"); - Configuration telestaxProxyConfiguration = configuration.subset("runtime-settings").subset("telestax-proxy"); - - phoneNumberProvisioningManager = (PhoneNumberProvisioningManager) new ObjectFactory(getClass().getClassLoader()) - .getObjectInstance(phoneNumberProvisioningManagerClass); - ContainerConfiguration containerConfiguration = new ContainerConfiguration(getOutboundInterfaces()); - phoneNumberProvisioningManager.init(phoneNumberProvisioningConfiguration, telestaxProxyConfiguration, containerConfiguration); - context.setAttribute("phoneNumberProvisioningManager", phoneNumberProvisioningManager); - } - Configuration callbackUrlsConfiguration = configuration.subset("phone-number-provisioning").subset("callback-urls"); - phoneNumberParameters = new PhoneNumberParameters( - callbackUrlsConfiguration.getString("voice[@url]"), - callbackUrlsConfiguration.getString("voice[@method]"), false, - callbackUrlsConfiguration.getString("sms[@url]"), - callbackUrlsConfiguration.getString("sms[@method]"), - callbackUrlsConfiguration.getString("fax[@url]"), - callbackUrlsConfiguration.getString("fax[@method]"), - callbackUrlsConfiguration.getString("ussd[@url]"), - callbackUrlsConfiguration.getString("ussd[@method]")); - - final IncomingPhoneNumberConverter converter = new IncomingPhoneNumberConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.serializeNulls(); - builder.registerTypeAdapter(IncomingPhoneNumber.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new IncomingPhoneNumberListConverter(configuration)); - xstream.registerConverter(new AvailableCountriesConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - private IncomingPhoneNumber createFrom(final Sid accountSid, final MultivaluedMap data) { - final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); - final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); - builder.setSid(sid); - builder.setAccountSid(accountSid); - String phoneNumber = data.getFirst("PhoneNumber"); - builder.setPhoneNumber(phoneNumber); - builder.setFriendlyName(getFriendlyName(phoneNumber, data)); - final String apiVersion = getApiVersion(data); - builder.setApiVersion(apiVersion); - builder.setVoiceUrl(getUrl("VoiceUrl", data)); - builder.setVoiceMethod(getMethod("VoiceMethod", data)); - builder.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); - builder.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); - builder.setStatusCallback(getUrl("StatusCallback", data)); - builder.setStatusCallbackMethod(getMethod("StatusCallbackMethod", data)); - builder.setHasVoiceCallerIdLookup(getHasVoiceCallerIdLookup(data)); - builder.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); - builder.setSmsUrl(getUrl("SmsUrl", data)); - builder.setSmsMethod(getMethod("SmsMethod", data)); - builder.setSmsFallbackUrl(getUrl("SmsFallbackUrl", data)); - builder.setSmsFallbackMethod(getMethod("SmsFallbackMethod", data)); - builder.setSmsApplicationSid(getSid("SmsApplicationSid", data)); - final Configuration configuration = this.configuration.subset("runtime-settings"); - String rootUri = configuration.getString("root-uri"); - rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); - final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(apiVersion).append("/Accounts/").append(accountSid.toString()) - .append("/IncomingPhoneNumbers/").append(sid.toString()); - builder.setUri(URI.create(buffer.toString())); - return builder.build(); - } - - private String e164(String number) throws NumberParseException { - final PhoneNumberUtil numbersUtil = PhoneNumberUtil.getInstance(); - if(!number.startsWith("+")) { - number = "+" + number; - } - final PhoneNumber result = numbersUtil.parse(number, "US"); - return numbersUtil.format(result, PhoneNumberFormat.E164); - } - - private String getFriendlyName(final String phoneNumber, final MultivaluedMap data) { - String friendlyName = phoneNumber; - if (data.containsKey("FriendlyName")) { - friendlyName = data.getFirst("FriendlyName"); - } - return friendlyName; - } - - protected Response getIncomingPhoneNumber(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); - if (incomingPhoneNumber == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - protected Response getAvailableCountries(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - List countries = phoneNumberProvisioningManager.getAvailableCountries(); - if(countries == null) { - countries = new ArrayList(); - countries.add("US"); - } - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(countries), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new AvailableCountriesList(countries)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - - protected Response getIncomingPhoneNumbers(final String accountSid, final String phoneNumberFilter, final String friendlyNameFilter, - PhoneNumberType phoneNumberType, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - IncomingPhoneNumberFilter incomingPhoneNumberFilter = new IncomingPhoneNumberFilter(accountSid, friendlyNameFilter, phoneNumberFilter); - final List incomingPhoneNumbers = dao.getIncomingPhoneNumbersByFilter(incomingPhoneNumberFilter); - - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(incomingPhoneNumbers), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new IncomingPhoneNumberList(incomingPhoneNumbers)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - - protected Response putIncomingPhoneNumber(final String accountSid, final MultivaluedMap data, - PhoneNumberType phoneNumberType, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Create:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - try { - validate(data); - } catch (final NullPointerException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - String number = data.getFirst("PhoneNumber"); - // cater to SIP numbers - boolean isRealNumber = true; - try { - number = e164(number); - } catch (NumberParseException e) { - isRealNumber = false; - } - IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(number); - if (incomingPhoneNumber == null) { - incomingPhoneNumber = createFrom(new Sid(accountSid), data); - phoneNumberParameters.setPhoneNumberType(phoneNumberType); - boolean isDidAssigned = true; - if(isRealNumber) { - isDidAssigned = phoneNumberProvisioningManager.buyNumber(number, phoneNumberParameters); - } - if(isDidAssigned) { - dao.addIncomingPhoneNumber(incomingPhoneNumber); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } - } - } - return status(BAD_REQUEST).entity("21452").build(); - } - - public Response updateIncomingPhoneNumber(final String accountSid, final String sid, - final MultivaluedMap data, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Modify:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); - String number = incomingPhoneNumber.getPhoneNumber(); - // cater to SIP numbers - boolean isRealNumber = true; - try { - number = e164(number); - } catch (NumberParseException e) { - isRealNumber = false; - } - boolean updated = true; - if(isRealNumber) { - updated = phoneNumberProvisioningManager.updateNumber(incomingPhoneNumber.getPhoneNumber(), phoneNumberParameters); - } - if(updated) { - dao.updateIncomingPhoneNumber(update(incomingPhoneNumber, data)); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - return status(BAD_REQUEST).entity("21452").build(); - } - - private void validate(final MultivaluedMap data) throws RuntimeException { - if (!data.containsKey("PhoneNumber") && !data.containsKey("AreaCode")) { - throw new NullPointerException("Phone number can not be null."); - } - } - - private IncomingPhoneNumber update(final IncomingPhoneNumber incomingPhoneNumber, final MultivaluedMap data) { - if (data.containsKey("ApiVersion")) { - incomingPhoneNumber.setApiVersion(getApiVersion(data)); - } - if (data.containsKey("FriendlyName")) { - incomingPhoneNumber.setFriendlyName(data.getFirst("FriendlyName")); - } - if (data.containsKey("VoiceUrl")) { - incomingPhoneNumber.setVoiceUrl(getUrl("VoiceUrl", data)); - } - if (data.containsKey("VoiceMethod")) { - incomingPhoneNumber.setVoiceMethod(getMethod("VoiceMethod", data)); - } - if (data.containsKey("VoiceFallbackUrl")) { - incomingPhoneNumber.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); - } - if (data.containsKey("VoiceFallbackMethod")) { - incomingPhoneNumber.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); - } - if (data.containsKey("StatusCallback")) { - incomingPhoneNumber.setStatusCallback(getUrl("StatusCallback", data)); - } - if (data.containsKey("StatusCallbackMethod")) { - incomingPhoneNumber.setStatusCallbackMethod(getMethod("StatusCallbackMethod", data)); - } - if (data.containsKey("VoiceCallerIdLookup")) { - incomingPhoneNumber.setHasVoiceCallerIdLookup(getHasVoiceCallerIdLookup(data)); - } - if (data.containsKey("VoiceApplicationSid")) { - incomingPhoneNumber.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); - } - if (data.containsKey("SmsUrl")) { - incomingPhoneNumber.setSmsUrl(getUrl("SmsUrl", data)); - } - if (data.containsKey("SmsMethod")) { - incomingPhoneNumber.setSmsMethod(getMethod("SmsMethod", data)); - } - if (data.containsKey("SmsFallbackUrl")) { - incomingPhoneNumber.setSmsFallbackUrl(getUrl("SmsFallbackUrl", data)); - } - if (data.containsKey("SmsFallbackMethod")) { - incomingPhoneNumber.setSmsFallbackMethod(getMethod("SmsFallbackMethod", data)); - } - if (data.containsKey("SmsApplicationSid")) { - incomingPhoneNumber.setSmsApplicationSid(getSid("SmsApplicationSid", data)); - } - - if (data.containsKey("VoiceCapable")) { - incomingPhoneNumber.setVoiceCapable(Boolean.parseBoolean(data.getFirst("VoiceCapable"))); - } - - if (data.containsKey("SmsCapable")) { - incomingPhoneNumber.setSmsCapable(Boolean.parseBoolean(data.getFirst("SmsCapable"))); - } - - if (data.containsKey("MmsCapable")) { - incomingPhoneNumber.setMmsCapable(Boolean.parseBoolean(data.getFirst("MmsCapable"))); - } - - if (data.containsKey("FaxCapable")) { - incomingPhoneNumber.setFaxCapable(Boolean.parseBoolean(data.getFirst("FaxCapable"))); - } - - incomingPhoneNumber.setDateUpdated(DateTime.now()); - return incomingPhoneNumber; - } - - public Response deleteIncomingPhoneNumber(final String accountSid, final String sid) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Delete:IncomingPhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); - String number = incomingPhoneNumber.getPhoneNumber(); - // cater to SIP numbers - boolean isRealNumber = true; - try { - number = e164(number); - } catch (NumberParseException e) { - isRealNumber = false; - } - if(isRealNumber) { - phoneNumberProvisioningManager.cancelNumber(number); - } - dao.removeIncomingPhoneNumber(new Sid(sid)); - return noContent().build(); - } - - @SuppressWarnings("unchecked") - private List getOutboundInterfaces() { - final List uris = (List) context.getAttribute(SipServlet.OUTBOUND_INTERFACES); - return uris; - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsEndpoint.java deleted file mode 100644 index 72c6912ecc..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsEndpoint.java +++ /dev/null @@ -1,127 +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.mobicents.servlet.restcomm.http; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import java.util.List; - -import static javax.ws.rs.core.MediaType.*; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.NotificationList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.NotificationConverter; -import org.mobicents.servlet.restcomm.http.converter.NotificationListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class NotificationsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected NotificationsDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - public NotificationsEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - dao = storage.getNotificationsDao(); - accountsDao = storage.getAccountsDao(); - final NotificationConverter converter = new NotificationConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Notification.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new NotificationListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - protected Response getNotification(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Notifications"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Notification notification = dao.getNotification(new Sid(sid)); - if (notification == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(notification), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(notification); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - protected Response getNotifications(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Notifications"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List notifications = dao.getNotifications(new Sid(accountSid)); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(notifications), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new NotificationList(notifications)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsEndpoint.java deleted file mode 100644 index 7d6621e28c..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsEndpoint.java +++ /dev/null @@ -1,127 +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.mobicents.servlet.restcomm.http; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import java.util.List; - -import static javax.ws.rs.core.MediaType.*; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.RecordingsDao; -import org.mobicents.servlet.restcomm.entities.Recording; -import org.mobicents.servlet.restcomm.entities.RecordingList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.RecordingConverter; -import org.mobicents.servlet.restcomm.http.converter.RecordingListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class RecordingsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected RecordingsDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - public RecordingsEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - dao = storage.getRecordingsDao(); - accountsDao = storage.getAccountsDao(); - final RecordingConverter converter = new RecordingConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Recording.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new RecordingListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - protected Response getRecording(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Recordings"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Recording recording = dao.getRecording(new Sid(sid)); - if (recording == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(recording), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(recording); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - protected Response getRecordings(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Recordings"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List recordings = dao.getRecordings(new Sid(accountSid)); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(recordings), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new RecordingList(recordings)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsXmlEndpoint.java deleted file mode 100644 index b39d2e50d5..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsXmlEndpoint.java +++ /dev/null @@ -1,73 +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.mobicents.servlet.restcomm.http; - -import java.io.File; - -import javax.ws.rs.GET; -import static javax.ws.rs.core.MediaType.*; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Accounts/{accountSid}/Recordings") -@ThreadSafe -public final class RecordingsXmlEndpoint extends RecordingsEndpoint { - public RecordingsXmlEndpoint() { - super(); - } - - @Path("/{sid}.json") - @GET - public Response getRecordingAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { - return getRecording(accountSid, sid, APPLICATION_JSON_TYPE); - } - - @Path("/{sid}.wav") - @GET - public Response getRecordingAsWav(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { - final StringBuilder buffer = new StringBuilder(); - buffer.append(baseRecordingsPath).append(sid).append(".wav"); - final File file = new File(buffer.toString()); - if (!file.exists()) { - return status(NOT_FOUND).build(); - } else { - return ok(file, "audio/wav").build(); - } - } - - @Path("/{sid}") - @GET - public Response getRecordingAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { - return getRecording(accountSid, sid, APPLICATION_XML_TYPE); - } - - @GET - public Response getRecordings(@PathParam("accountSid") final String accountSid) { - return getRecordings(accountSid, APPLICATION_XML_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesEndpoint.java deleted file mode 100644 index 2fcc31e767..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesEndpoint.java +++ /dev/null @@ -1,327 +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.mobicents.servlet.restcomm.http; - -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.util.Timeout; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.thoughtworks.xstream.XStream; - -import java.math.BigDecimal; -import java.net.URI; -import java.util.Currency; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.MediaType; - -import static akka.pattern.Patterns.ask; -import static javax.ws.rs.core.MediaType.*; - -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; -import org.mobicents.servlet.restcomm.entities.SmsMessageList; -import org.mobicents.servlet.restcomm.entities.SmsMessage.Status; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.http.converter.SmsMessageConverter; -import org.mobicents.servlet.restcomm.http.converter.SmsMessageListConverter; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.sms.CreateSmsSession; -import org.mobicents.servlet.restcomm.sms.SmsServiceResponse; -import org.mobicents.servlet.restcomm.sms.SmsSessionAttribute; -import org.mobicents.servlet.restcomm.sms.SmsSessionInfo; -import org.mobicents.servlet.restcomm.sms.SmsSessionRequest; -import org.mobicents.servlet.restcomm.sms.SmsSessionResponse; -import org.mobicents.servlet.restcomm.util.StringUtils; - -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.Duration; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class SmsMessagesEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected ActorSystem system; - protected Configuration configuration; - protected ActorRef aggregator; - protected SmsMessagesDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - private boolean normalizePhoneNumbers; - - public SmsMessagesEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - dao = storage.getSmsMessagesDao(); - accountsDao = storage.getAccountsDao(); - aggregator = (ActorRef) context.getAttribute("org.mobicents.servlet.restcomm.sms.SmsService"); - system = (ActorSystem) context.getAttribute(ActorSystem.class.getName()); - super.init(configuration); - final SmsMessageConverter converter = new SmsMessageConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(SmsMessage.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new SmsMessageListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - - normalizePhoneNumbers = configuration.getBoolean("normalize-numbers-for-outbound-calls"); - } - - protected Response getSmsMessage(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:SmsMessages"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final SmsMessage smsMessage = dao.getSmsMessage(new Sid(sid)); - if (smsMessage == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(smsMessage), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(smsMessage); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - protected Response getSmsMessages(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:SmsMessages"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List smsMessages = dao.getSmsMessages(new Sid(accountSid)); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(smsMessages), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new SmsMessageList(smsMessages)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - - private void normalize(final MultivaluedMap data) throws IllegalArgumentException { - final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); - final String from = data.getFirst("From"); - data.remove("From"); - try { - data.putSingle("From", phoneNumberUtil.format(phoneNumberUtil.parse(from, "US"), PhoneNumberFormat.E164)); - } catch (final NumberParseException exception) { - throw new IllegalArgumentException(exception); - } - final String to = data.getFirst("To"); - data.remove("To"); - try { - data.putSingle("To", phoneNumberUtil.format(phoneNumberUtil.parse(to, "US"), PhoneNumberFormat.E164)); - } catch (final NumberParseException exception) { - throw new IllegalArgumentException(exception); - } - final String body = data.getFirst("Body"); - if (body.getBytes().length > 160) { - data.remove("Body"); - data.putSingle("Body", body.substring(0, 159)); - } - } - - @SuppressWarnings("unchecked") - protected Response putSmsMessage(final String accountSid, final MultivaluedMap data, - final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Create:SmsMessages"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - try { - validate(data); - if(normalizePhoneNumbers) - normalize(data); - } catch (final RuntimeException exception) { - return status(BAD_REQUEST).entity(exception.getMessage()).build(); - } - final String sender = data.getFirst("From"); - final String recipient = data.getFirst("To"); - final String body = data.getFirst("Body"); - ConcurrentHashMap customRestOutgoingHeaderMap = new ConcurrentHashMap(); - Iterator iter = data.keySet().iterator(); - while (iter.hasNext()) { - String name = iter.next(); - if (name.startsWith("X-")){ - customRestOutgoingHeaderMap.put(name, data.getFirst(name)); - } - } - final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); - try { - Future future = (Future) ask(aggregator, new CreateSmsSession(), expires); - Object object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); - Class klass = object.getClass(); - if (SmsServiceResponse.class.equals(klass)) { - final SmsServiceResponse smsServiceResponse = (SmsServiceResponse) object; - if (smsServiceResponse.succeeded()) { - // Create an SMS record for the text message. - final SmsMessage record = sms(new Sid(accountSid), getApiVersion(data), sender, recipient, body, - SmsMessage.Status.SENDING, SmsMessage.Direction.OUTBOUND_API); - dao.addSmsMessage(record); - // Send the sms. - final ActorRef session = smsServiceResponse.get(); - final ActorRef observer = observer(); - session.tell(new Observe(observer), observer); - session.tell(new SmsSessionAttribute("record", record), null); - final SmsSessionRequest request = new SmsSessionRequest(sender, recipient, body, customRestOutgoingHeaderMap); - session.tell(request, null); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(record), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(record); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - return status(INTERNAL_SERVER_ERROR).build(); - } catch (final Exception exception) { - return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); - } - } - - private SmsMessage sms(final Sid accountSid, final String apiVersion, final String sender, final String recipient, - final String body, final SmsMessage.Status status, final SmsMessage.Direction direction) { - final SmsMessage.Builder builder = SmsMessage.builder(); - final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); - builder.setSid(sid); - builder.setAccountSid(accountSid); - builder.setSender(sender); - builder.setRecipient(recipient); - builder.setBody(body); - builder.setStatus(status); - builder.setDirection(direction); - builder.setPrice(new BigDecimal(0.00)); - // TODO - this needs to be added as property to Configuration somehow - builder.setPriceUnit(Currency.getInstance("USD")); - builder.setApiVersion(apiVersion); - String rootUri = configuration.getString("root-uri"); - rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); - final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(apiVersion).append("/Accounts/"); - buffer.append(accountSid.toString()).append("/SMS/Messages/"); - buffer.append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - return builder.build(); - } - - private void validate(final MultivaluedMap data) throws NullPointerException { - if (!data.containsKey("From")) { - throw new NullPointerException("From can not be null."); - } else if (!data.containsKey("To")) { - throw new NullPointerException("To can not be null."); - } else if (!data.containsKey("Body")) { - throw new NullPointerException("Body can not be null."); - } - } - - private ActorRef observer() { - return system.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new SmsSessionObserver(); - } - })); - } - - private final class SmsSessionObserver extends UntypedActor { - public SmsSessionObserver() { - super(); - } - - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - if (SmsSessionResponse.class.equals(klass)) { - final SmsSessionResponse response = (SmsSessionResponse) message; - final SmsSessionInfo info = response.info(); - SmsMessage record = (SmsMessage) info.attributes().get("record"); - if (response.succeeded()) { - final DateTime now = DateTime.now(); - record = record.setDateSent(now); - record = record.setStatus(Status.SENT); - } else { - record = record.setStatus(Status.FAILED); - } - dao.updateSmsMessage(record); - final UntypedActorContext context = getContext(); - final ActorRef self = self(); - context.stop(self); - } - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsEndpoint.java deleted file mode 100644 index c8d4666128..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsEndpoint.java +++ /dev/null @@ -1,127 +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.mobicents.servlet.restcomm.http; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; - -import java.util.List; - -import static javax.ws.rs.core.MediaType.*; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.TranscriptionsDao; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.Transcription; -import org.mobicents.servlet.restcomm.entities.TranscriptionList; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.http.converter.TranscriptionConverter; -import org.mobicents.servlet.restcomm.http.converter.TranscriptionListConverter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@NotThreadSafe -public abstract class TranscriptionsEndpoint extends AbstractEndpoint { - @Context - protected ServletContext context; - protected Configuration configuration; - protected TranscriptionsDao dao; - protected Gson gson; - protected XStream xstream; - protected AccountsDao accountsDao; - - public TranscriptionsEndpoint() { - super(); - } - - @PostConstruct - public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - configuration = configuration.subset("runtime-settings"); - super.init(configuration); - dao = storage.getTranscriptionsDao(); - accountsDao = storage.getAccountsDao(); - final TranscriptionConverter converter = new TranscriptionConverter(configuration); - final GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Transcription.class, converter); - builder.setPrettyPrinting(); - gson = builder.create(); - xstream = new XStream(); - xstream.alias("RestcommResponse", RestCommResponse.class); - xstream.registerConverter(converter); - xstream.registerConverter(new TranscriptionListConverter(configuration)); - xstream.registerConverter(new RestCommResponseConverter(configuration)); - } - - protected Response getTranscription(final String accountSid, final String sid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Transcriptions"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final Transcription transcription = dao.getTranscription(new Sid(sid)); - if (transcription == null) { - return status(NOT_FOUND).build(); - } else { - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(transcription), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(transcription); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } - } - - protected Response getTranscriptions(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:Transcriptions"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - final List transcriptions = dao.getTranscriptions(new Sid(accountSid)); - if (APPLICATION_JSON_TYPE == responseType) { - return ok(gson.toJson(transcriptions), APPLICATION_JSON).build(); - } else if (APPLICATION_XML_TYPE == responseType) { - final RestCommResponse response = new RestCommResponse(new TranscriptionList(transcriptions)); - return ok(xstream.toXML(response), APPLICATION_XML).build(); - } else { - return null; - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsXmlEndpoint.java deleted file mode 100644 index dbdded6cb8..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsXmlEndpoint.java +++ /dev/null @@ -1,72 +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.mobicents.servlet.restcomm.http; - -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import static javax.ws.rs.core.MediaType.*; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.shiro.authz.AuthorizationException; - -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Path("/Accounts/{accountSid}/Transcriptions") -public final class TranscriptionsXmlEndpoint extends TranscriptionsEndpoint { - public TranscriptionsXmlEndpoint() { - super(); - } - - @Path("/{sid}") - @DELETE - public Response deleteTranscription(@PathParam("accountSid") String accountSid, @PathParam("sid") String sid) { - try { - secure(super.accountsDao.getAccount(accountSid), "RestComm:Delete:Transcriptions"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } - dao.removeTranscription(new Sid(sid)); - return ok().build(); - } - - @Path("/{sid}.json") - @GET - public Response getTranscriptionAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { - return getTranscription(accountSid, sid, APPLICATION_JSON_TYPE); - } - - @Path("/{sid}") - @GET - public Response getTranscriptionAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { - return getTranscription(accountSid, sid, APPLICATION_XML_TYPE); - } - - @GET - public Response getTranscriptions(@PathParam("accountSid") final String accountSid) { - return getTranscriptions(accountSid, APPLICATION_XML_TYPE); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/Downloader.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/Downloader.java deleted file mode 100644 index c785592e72..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/Downloader.java +++ /dev/null @@ -1,178 +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.mobicents.servlet.restcomm.http.client; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.params.ClientPNames; -import org.apache.http.client.params.CookiePolicy; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.impl.client.DefaultHttpClient; - -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class Downloader extends UntypedActor { - - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - - public Downloader() { - super(); - } - - public HttpResponseDescriptor fetch(final HttpRequestDescriptor descriptor) throws IllegalArgumentException, IOException, - URISyntaxException { - int code = -1; - HttpRequest request = null; - HttpResponse response = null; - HttpRequestDescriptor temp = descriptor; - do { - final DefaultHttpClient client = new DefaultHttpClient(); - client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); -// client.getParams().setParameter("http.protocol.content-charset", "UTF-8"); - request = request(temp); -// request.setHeader(CoreProtocolPNames.HTTP_CONTENT_CHARSET, Consts.UTF_8.name()); - response = client.execute((HttpUriRequest) request); - code = response.getStatusLine().getStatusCode(); - if (isRedirect(code)) { - final Header header = response.getFirstHeader(HttpHeaders.LOCATION); - if (header != null) { - final String location = header.getValue(); - final URI uri = URI.create(location); - temp = new HttpRequestDescriptor(uri, temp.getMethod(), temp.getParameters()); - continue; - } else { - break; - } - } - } while (isRedirect(code)); - if (isHttpError(code)) { - String requestUrl = request.getRequestLine().getUri(); - String errorReason = response.getStatusLine().getReasonPhrase(); - String httpErrorMessage = String.format( - "Error while fetching http resource: %s \n Http error code: %d \n Http error message: %s", requestUrl, - code, errorReason); - logger.warning(httpErrorMessage); - } - return response(request, response); - } - - private boolean isRedirect(final int code) { - return HttpStatus.SC_MOVED_PERMANENTLY == code || HttpStatus.SC_MOVED_TEMPORARILY == code - || HttpStatus.SC_SEE_OTHER == code || HttpStatus.SC_TEMPORARY_REDIRECT == code; - } - - private boolean isHttpError(final int code) { - return (code >= 400); - } - - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - final ActorRef self = self(); - final ActorRef sender = sender(); - if (HttpRequestDescriptor.class.equals(klass)) { - final HttpRequestDescriptor request = (HttpRequestDescriptor) message; - DownloaderResponse response = null; - try { - response = new DownloaderResponse(fetch(request)); - } catch (final Exception exception) { - response = new DownloaderResponse(exception); - } - if (sender != null) { - sender.tell(response, self); - } - } - } - - public HttpUriRequest request(final HttpRequestDescriptor descriptor) throws IllegalArgumentException, URISyntaxException, - UnsupportedEncodingException { - final URI uri = descriptor.getUri(); - final String method = descriptor.getMethod(); - if ("GET".equalsIgnoreCase(method)) { - final String query = descriptor.getParametersAsString(); - URI result = null; - if (query != null && !query.isEmpty()) { - result = new URIBuilder() - .setScheme(uri.getScheme()) - .setHost(uri.getHost()) - .setPort(uri.getPort()) - .setPath(uri.getPath()) - .setQuery(query) - .build(); - } else { - result = uri; - } - return new HttpGet(result); - } else if ("POST".equalsIgnoreCase(method)) { - final List parameters = descriptor.getParameters(); - final HttpPost post = new HttpPost(uri); - post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8")); - return post; - } else { - throw new IllegalArgumentException(method + " is not a supported downloader method."); - } - } - - private HttpResponseDescriptor response(final HttpRequest request, final HttpResponse response) throws IOException { - final HttpResponseDescriptor.Builder builder = HttpResponseDescriptor.builder(); - final URI uri = URI.create(request.getRequestLine().getUri()); - builder.setURI(uri); - builder.setStatusCode(response.getStatusLine().getStatusCode()); - builder.setStatusDescription(response.getStatusLine().getReasonPhrase()); - builder.setHeaders(response.getAllHeaders()); - final HttpEntity entity = response.getEntity(); - if (entity != null) { - final Header contentEncoding = entity.getContentEncoding(); - if (contentEncoding != null) { - builder.setContentEncoding(contentEncoding.getValue()); - } - final Header contentType = entity.getContentType(); - if (contentType != null) { - builder.setContentType(contentType.getValue()); - } - builder.setContent(entity.getContent()); - builder.setContentLength(entity.getContentLength()); - builder.setIsChunked(entity.isChunked()); - } - return builder.build(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AbstractConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AbstractConverter.java deleted file mode 100644 index 6d14981321..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AbstractConverter.java +++ /dev/null @@ -1,543 +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.mobicents.servlet.restcomm.http.converter; - -import java.math.BigDecimal; -import java.net.URI; -import java.text.SimpleDateFormat; -import java.util.Currency; -import java.util.Locale; - -import org.apache.commons.configuration.Configuration; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.entities.Sid; - -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.thoughtworks.xstream.converters.Converter; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author gvagenas - * @author Jean Deruelle - */ -public abstract class AbstractConverter implements Converter { - protected final Configuration configuration; - - public AbstractConverter(final Configuration configuration) { - super(); - this.configuration = configuration; - } - - @SuppressWarnings("rawtypes") - @Override - public abstract boolean canConvert(Class klass); - - @Override - public abstract void marshal(final Object object, HierarchicalStreamWriter writer, MarshallingContext context); - - @Override - public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - return null; - } - - protected void writeAccountSid(final Sid accountSid, final HierarchicalStreamWriter writer) { - writer.startNode("AccountSid"); - writer.setValue(accountSid.toString()); - writer.endNode(); - } - - protected void writeAccountSid(final Sid accountSid, final JsonObject object) { - object.addProperty("account_sid", accountSid.toString()); - } - - protected void writeApiVersion(final String apiVersion, final HierarchicalStreamWriter writer) { - writer.startNode("ApiVersion"); - writer.setValue(apiVersion); - writer.endNode(); - } - - protected void writeApiVersion(final String apiVersion, final JsonObject object) { - object.addProperty("api_version", apiVersion); - } - - protected void writeCallSid(final Sid callSid, final HierarchicalStreamWriter writer) { - if (callSid != null) { - writer.startNode("CallSid"); - writer.setValue(callSid.toString()); - writer.endNode(); - } - } - - protected void writeCallSid(final Sid callSid, final JsonObject object) { - if (callSid != null) - object.addProperty("call_sid", callSid.toString()); - } - - protected void writeDateCreated(final DateTime dateCreated, final HierarchicalStreamWriter writer) { - writer.startNode("DateCreated"); - writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateCreated.toDate())); - writer.endNode(); - } - - protected void writeDateCreated(final DateTime dateCreated, final JsonObject object) { - object.addProperty("date_created", new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateCreated.toDate())); - } - - protected void writeDateUpdated(final DateTime dateUpdated, final HierarchicalStreamWriter writer) { - writer.startNode("DateUpdated"); - writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateUpdated.toDate())); - writer.endNode(); - } - - protected void writeDateUpdated(final DateTime dateUpdated, final JsonObject object) { - object.addProperty("date_updated", new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateUpdated.toDate())); - } - - protected void writeDuration(final double duration, final HierarchicalStreamWriter writer) { - writer.startNode("Duration"); - writer.setValue(Double.toString(duration)); - writer.endNode(); - } - - protected void writeDuration(final double duration, final JsonObject object) { - object.addProperty("duration", Double.toString(duration)); - } - - protected void writeFriendlyName(final String friendlyName, final HierarchicalStreamWriter writer) { - writer.startNode("FriendlyName"); - writer.setValue(friendlyName); - writer.endNode(); - } - - protected void writeFriendlyName(final String friendlyName, final JsonObject object) { - object.addProperty("friendly_name", friendlyName); - } - - protected void writeFrom(final String from, final HierarchicalStreamWriter writer) { - writer.startNode("From"); - writer.setValue(from); - writer.endNode(); - } - - protected void writeFrom(final String from, final JsonObject object) { - object.addProperty("from", from); - } - - protected void writePhoneNumber(final String phoneNumber, final HierarchicalStreamWriter writer) { - writer.startNode("PhoneNumber"); - writer.setValue(phoneNumber); - writer.endNode(); - } - - protected void writePhoneNumber(final String phoneNumber, final JsonObject object) { - object.addProperty("phone_number", phoneNumber); - } - - protected void writePrice(final BigDecimal price, final HierarchicalStreamWriter writer) { - writer.startNode("Price"); - writer.setValue(price.toString()); - writer.endNode(); - } - - protected void writePrice(final BigDecimal price, final JsonObject object) { - object.addProperty("price", price.toString()); - } - - protected void writePriceUnit(final Currency priceUnit, final HierarchicalStreamWriter writer) { - writer.startNode("PriceUnit"); - if (priceUnit != null) { - writer.setValue(priceUnit.toString()); - } - writer.endNode(); - } - - protected void writePriceUnit(final Currency priceUnit, final JsonObject object) { - if (priceUnit != null) { - object.addProperty("price_unit", priceUnit.toString()); - } else { - object.add("price_unit", JsonNull.INSTANCE); - } - } - - protected void writeSid(final Sid sid, final HierarchicalStreamWriter writer) { - writer.startNode("Sid"); - writer.setValue(sid.toString()); - writer.endNode(); - } - - protected void writeSid(final Sid sid, final JsonObject object) { - object.addProperty("sid", sid.toString()); - } - - protected void writeSmsFallbackUrl(final URI smsFallbackUrl, final HierarchicalStreamWriter writer) { - writer.startNode("SmsFallbackUrl"); - if (smsFallbackUrl != null) { - writer.setValue(smsFallbackUrl.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeSmsFallbackUrl(final URI smsFallbackUrl, final JsonObject object) { - if (smsFallbackUrl != null) { - object.addProperty("sms_fallback_url", smsFallbackUrl.toString()); - } else { - object.add("sms_fallback_url", JsonNull.INSTANCE); - } - } - - protected void writeSmsFallbackMethod(final String smsFallbackMethod, final HierarchicalStreamWriter writer) { - writer.startNode("SmsFallbackMethod"); - if (smsFallbackMethod != null) { - writer.setValue(smsFallbackMethod); - } - writer.endNode(); - } - - protected void writeSmsFallbackMethod(final String smsFallbackMethod, final JsonObject object) { - if (smsFallbackMethod != null) { - object.addProperty("sms_fallback_method", smsFallbackMethod); - } else { - object.add("sms_fallback_method", JsonNull.INSTANCE); - } - } - - protected void writeSmsUrl(final URI smsUrl, final HierarchicalStreamWriter writer) { - writer.startNode("SmsUrl"); - if (smsUrl != null) { - writer.setValue(smsUrl.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeSmsUrl(final URI smsUrl, final JsonObject object) { - if (smsUrl != null) { - object.addProperty("sms_url", smsUrl.toString()); - } else { - object.add("sms_url", JsonNull.INSTANCE); - } - } - - protected void writeSmsMethod(final String smsMethod, final HierarchicalStreamWriter writer) { - writer.startNode("SmsMethod"); - if (smsMethod != null) { - writer.setValue(smsMethod); - } - writer.endNode(); - } - - protected void writeSmsMethod(final String smsMethod, final JsonObject object) { - if (smsMethod != null) { - object.addProperty("sms_method", smsMethod); - } else { - object.add("sms_method", JsonNull.INSTANCE); - } - } - - protected void writeStatus(final String status, final HierarchicalStreamWriter writer) { - writer.startNode("Status"); - writer.setValue(status); - writer.endNode(); - } - - protected void writeStatus(final String status, final JsonObject object) { - object.addProperty("status", status); - } - - protected void writeStatusCallback(final URI statusCallback, final HierarchicalStreamWriter writer) { - writer.startNode("StatusCallback"); - if (statusCallback != null) { - writer.setValue(statusCallback.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeStatusCallback(final URI statusCallback, final JsonObject object) { - if (statusCallback != null) { - object.addProperty("status_callback", statusCallback.toString()); - } else { - object.add("status_callback", JsonNull.INSTANCE); - } - } - - protected void writeStatusCallbackMethod(final String statusCallbackMethod, final HierarchicalStreamWriter writer) { - writer.startNode("StatusCallbackMethod"); - if (statusCallbackMethod != null) { - writer.setValue(statusCallbackMethod); - } - writer.endNode(); - } - - protected void writeStatusCallbackMethod(final String statusCallbackMethod, final JsonObject object) { - if (statusCallbackMethod != null) { - object.addProperty("status_callback_method", statusCallbackMethod); - } else { - object.add("status_callback_method", JsonNull.INSTANCE); - } - } - - protected void writeTo(final String to, final HierarchicalStreamWriter writer) { - writer.startNode("To"); - writer.setValue(to); - writer.endNode(); - } - - protected void writeTo(final String to, final JsonObject object) { - object.addProperty("to", to); - } - - protected void writeTimeToLive(final int timeToLive, final HierarchicalStreamWriter writer) { - writer.startNode("TimeToLive"); - writer.setValue(Integer.toString(timeToLive)); - writer.endNode(); - } - - protected void writeTimeToLive(final int timeToLive, final JsonObject object) { - object.addProperty("time_to_live", timeToLive); - } - - protected void writeType(final String type, final HierarchicalStreamWriter writer) { - writer.startNode("Type"); - writer.setValue(type); - writer.endNode(); - } - - protected void writeType(final String type, final JsonObject object) { - object.addProperty("type", type); - } - - protected void writeUri(final URI uri, final HierarchicalStreamWriter writer) { - writer.startNode("Uri"); - writer.setValue(uri.toString()); - writer.endNode(); - } - - protected void writeUri(final URI uri, final JsonObject object) { - object.addProperty("uri", uri.toString() + ".json"); - } - - protected void writeUserName(final String userName, final HierarchicalStreamWriter writer) { - writer.startNode("UserName"); - writer.setValue(userName); - writer.endNode(); - } - - protected void writeUserName(final String userName, final JsonObject object) { - object.addProperty("user_name", userName); - } - - protected void writeVoiceApplicationSid(final Sid voiceApplicationSid, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceApplicationSid"); - if (voiceApplicationSid != null) { - writer.setValue(voiceApplicationSid.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeVoiceApplicationSid(final Sid voiceApplicationSid, final JsonObject object) { - if (voiceApplicationSid != null) { - object.addProperty("voice_application_sid", voiceApplicationSid.toString()); - } else { - object.add("voice_application_sid", JsonNull.INSTANCE); - } - } - - protected void writeVoiceCallerIdLookup(final boolean voiceCallerIdLookup, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceCallerIdLookup"); - writer.setValue(Boolean.toString(voiceCallerIdLookup)); - writer.endNode(); - } - - protected void writeVoiceCallerIdLookup(final boolean voiceCallerIdLookup, final JsonObject object) { - object.addProperty("voice_caller_id_lookup", voiceCallerIdLookup); - } - - protected void writeVoiceFallbackMethod(final String voiceFallbackMethod, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceFallbackMethod"); - if (voiceFallbackMethod != null) { - writer.setValue(voiceFallbackMethod); - } - writer.endNode(); - } - - protected void writeVoiceFallbackMethod(final String voiceFallbackMethod, final JsonObject object) { - if (voiceFallbackMethod != null) { - object.addProperty("voice_fallback_method", voiceFallbackMethod); - } else { - object.add("voice_fallback_method", JsonNull.INSTANCE); - } - } - - protected void writeVoiceFallbackUrl(final URI voiceFallbackUri, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceFallbackUrl"); - if (voiceFallbackUri != null) { - writer.setValue(voiceFallbackUri.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeVoiceFallbackUrl(final URI voiceFallbackUri, final JsonObject object) { - if (voiceFallbackUri != null) { - object.addProperty("voice_fallback_url", voiceFallbackUri.toString()); - } else { - object.add("voice_fallback_url", JsonNull.INSTANCE); - } - } - - protected void writeVoiceMethod(final String voiceMethod, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceMethod"); - if (voiceMethod != null) { - writer.setValue(voiceMethod); - } - writer.endNode(); - } - - protected void writeVoiceMethod(final String voiceMethod, final JsonObject object) { - if (voiceMethod != null) { - object.addProperty("voice_method", voiceMethod); - } else { - object.add("voice_method", JsonNull.INSTANCE); - } - } - - protected void writeVoiceUrl(final URI voiceUrl, final HierarchicalStreamWriter writer) { - writer.startNode("VoiceUrl"); - if (voiceUrl != null) { - writer.setValue(voiceUrl.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - protected void writeVoiceUrl(final URI voiceUrl, final JsonObject object) { - if (voiceUrl != null) { - object.addProperty("voice_url", voiceUrl.toString()); - } else { - object.add("voice_url", JsonNull.INSTANCE); - } - } - - protected void writeCapabilities(final Boolean voiceCapable, final Boolean smsCapable, final Boolean mmsCapable, - final Boolean faxCapable, final HierarchicalStreamWriter writer) { - writer.startNode("Capabilities"); - writeVoiceCapability(voiceCapable, writer); - writeSmsCapability(smsCapable, writer); - writeMmsCapability(mmsCapable, writer); - writeFaxCapability(faxCapable, writer); - writer.endNode(); - } - - protected void writeCapabilities(final Boolean voiceCapable, final Boolean smsCapable, final Boolean mmsCapable, - final Boolean faxCapable, final JsonObject object) { - JsonObject capabilities = new JsonObject(); - writeVoiceCapability(voiceCapable, capabilities); - writeSmsCapability(smsCapable, capabilities); - writeMmsCapability(mmsCapable, capabilities); - writeFaxCapability(faxCapable, capabilities); - object.add("capabilities", capabilities); - } - - protected void writeVoiceCapability(final Boolean voiceCapable, final HierarchicalStreamWriter writer) { - writer.startNode("Voice"); - if (voiceCapable == null) { - writer.setValue(Boolean.FALSE.toString()); - } else { - writer.setValue(voiceCapable.toString()); - } - writer.endNode(); - } - - protected void writeVoiceCapability(final Boolean voiceCapable, final JsonObject object) { - if (voiceCapable != null) { - object.addProperty("voice_capable", voiceCapable); - } else { - object.addProperty("voice_capable", Boolean.FALSE); - } - } - - protected void writeSmsCapability(final Boolean smsCapable, final HierarchicalStreamWriter writer) { - writer.startNode("Sms"); - if (smsCapable == null) { - writer.setValue(Boolean.FALSE.toString()); - } else { - writer.setValue(smsCapable.toString()); - } - writer.endNode(); - } - - protected void writeSmsCapability(final Boolean smsCapable, final JsonObject object) { - if (smsCapable != null) { - object.addProperty("sms_capable", smsCapable); - } else { - object.addProperty("sms_capable", Boolean.FALSE); - } - } - - protected void writeMmsCapability(final Boolean mmsCapable, final HierarchicalStreamWriter writer) { - writer.startNode("Mms"); - if (mmsCapable == null) { - writer.setValue(Boolean.FALSE.toString()); - } else { - writer.setValue(mmsCapable.toString()); - } - writer.endNode(); - } - - protected void writeMmsCapability(final Boolean mmsCapable, final JsonObject object) { - if (mmsCapable != null) { - object.addProperty("mms_capable", mmsCapable); - } else { - object.addProperty("mms_capable", Boolean.FALSE); - } - } - - protected void writeFaxCapability(final Boolean faxCapable, final HierarchicalStreamWriter writer) { - writer.startNode("Fax"); - if (faxCapable == null) { - writer.setValue(Boolean.FALSE.toString()); - } else { - writer.setValue(faxCapable.toString()); - } - writer.endNode(); - } - - protected void writeFaxCapability(final Boolean faxCapable, final JsonObject object) { - if (faxCapable != null) { - object.addProperty("fax_capable", faxCapable); - } else { - object.addProperty("fax_capable", Boolean.FALSE); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationConverter.java deleted file mode 100644 index 3e7b6f2e1f..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationConverter.java +++ /dev/null @@ -1,118 +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.mobicents.servlet.restcomm.http.converter; - -import java.lang.reflect.Type; -import java.net.URI; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Application; - -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class ApplicationConverter extends AbstractConverter implements JsonSerializer { - public ApplicationConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return Application.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final Application application = (Application) object; - writer.startNode("Application"); - writeSid(application.getSid(), writer); - writeDateCreated(application.getDateCreated(), writer); - writeDateUpdated(application.getDateUpdated(), writer); - writeFriendlyName(application.getFriendlyName(), writer); - writeAccountSid(application.getAccountSid(), writer); - writeApiVersion(application.getApiVersion(), writer); - writeVoiceUrl(application.getVoiceUrl(), writer); - writeVoiceMethod(application.getVoiceMethod(), writer); - writeVoiceFallbackUrl(application.getVoiceFallbackUrl(), writer); - writeVoiceFallbackMethod(application.getVoiceFallbackMethod(), writer); - writeStatusCallback(application.getStatusCallback(), writer); - writeStatusCallbackMethod(application.getStatusCallbackMethod(), writer); - writeVoiceCallerIdLookup(application.hasVoiceCallerIdLookup(), writer); - writeSmsUrl(application.getSmsUrl(), writer); - writeSmsMethod(application.getSmsMethod(), writer); - writeSmsFallbackUrl(application.getSmsFallbackUrl(), writer); - writeSmsFallbackMethod(application.getSmsFallbackMethod(), writer); - writeSmsStatusCallback(application.getSmsStatusCallback(), writer); - writeUri(application.getUri(), writer); - writer.endNode(); - } - - @Override - public JsonElement serialize(final Application application, final Type type, final JsonSerializationContext context) { - final JsonObject object = new JsonObject(); - writeSid(application.getSid(), object); - writeDateCreated(application.getDateCreated(), object); - writeDateUpdated(application.getDateUpdated(), object); - writeFriendlyName(application.getFriendlyName(), object); - writeAccountSid(application.getAccountSid(), object); - writeApiVersion(application.getApiVersion(), object); - writeVoiceUrl(application.getVoiceUrl(), object); - writeVoiceMethod(application.getVoiceMethod(), object); - writeVoiceFallbackUrl(application.getVoiceFallbackUrl(), object); - writeVoiceFallbackMethod(application.getVoiceFallbackMethod(), object); - writeStatusCallback(application.getStatusCallback(), object); - writeStatusCallbackMethod(application.getStatusCallbackMethod(), object); - writeVoiceCallerIdLookup(application.hasVoiceCallerIdLookup(), object); - writeSmsUrl(application.getSmsUrl(), object); - writeSmsMethod(application.getSmsMethod(), object); - writeSmsFallbackUrl(application.getSmsFallbackUrl(), object); - writeSmsFallbackMethod(application.getSmsFallbackMethod(), object); - writeSmsStatusCallback(application.getSmsStatusCallback(), object); - writeUri(application.getUri(), object); - return object; - } - - private void writeSmsStatusCallback(final URI smsStatusCallback, final HierarchicalStreamWriter writer) { - writer.startNode("SmsStatusCallback"); - if (smsStatusCallback != null) { - writer.setValue(smsStatusCallback.toString()); - } - writer.endNode(); - } - - private void writeSmsStatusCallback(final URI smsStatusCallback, final JsonObject object) { - if (smsStatusCallback != null) { - object.addProperty("sms_status_callback", smsStatusCallback.toString()); - } else { - object.add("sms_status_callback", JsonNull.INSTANCE); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberConverter.java deleted file mode 100644 index f89e387461..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberConverter.java +++ /dev/null @@ -1,127 +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.mobicents.servlet.restcomm.http.converter; - -import java.lang.reflect.Type; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.Sid; - -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class IncomingPhoneNumberConverter extends AbstractConverter implements JsonSerializer { - public IncomingPhoneNumberConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return IncomingPhoneNumber.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final IncomingPhoneNumber incomingPhoneNumber = (IncomingPhoneNumber) object; - writer.startNode("IncomingPhoneNumber"); - writeSid(incomingPhoneNumber.getSid(), writer); - writeAccountSid(incomingPhoneNumber.getAccountSid(), writer); - writeFriendlyName(incomingPhoneNumber.getFriendlyName(), writer); - writePhoneNumber(incomingPhoneNumber.getPhoneNumber(), writer); - writeVoiceUrl(incomingPhoneNumber.getVoiceUrl(), writer); - writeVoiceMethod(incomingPhoneNumber.getVoiceMethod(), writer); - writeVoiceFallbackUrl(incomingPhoneNumber.getVoiceFallbackUrl(), writer); - writeVoiceFallbackMethod(incomingPhoneNumber.getVoiceFallbackMethod(), writer); - writeStatusCallback(incomingPhoneNumber.getStatusCallback(), writer); - writeStatusCallbackMethod(incomingPhoneNumber.getStatusCallbackMethod(), writer); - writeVoiceCallerIdLookup(incomingPhoneNumber.hasVoiceCallerIdLookup(), writer); - writeVoiceApplicationSid(incomingPhoneNumber.getVoiceApplicationSid(), writer); - writeDateCreated(incomingPhoneNumber.getDateCreated(), writer); - writeDateUpdated(incomingPhoneNumber.getDateUpdated(), writer); - writeSmsUrl(incomingPhoneNumber.getSmsUrl(), writer); - writeSmsMethod(incomingPhoneNumber.getSmsMethod(), writer); - writeSmsFallbackUrl(incomingPhoneNumber.getSmsFallbackUrl(), writer); - writeSmsFallbackMethod(incomingPhoneNumber.getSmsFallbackMethod(), writer); - writeSmsApplicationSid(incomingPhoneNumber.getSmsApplicationSid(), writer); - writeCapabilities(incomingPhoneNumber.isVoiceCapable(), incomingPhoneNumber.isSmsCapable(), incomingPhoneNumber.isMmsCapable(), incomingPhoneNumber.isFaxCapable(), writer); - writeApiVersion(incomingPhoneNumber.getApiVersion(), writer); - writeUri(incomingPhoneNumber.getUri(), writer); - writer.endNode(); - } - - @Override - public JsonElement serialize(final IncomingPhoneNumber incomingPhoneNumber, final Type type, - final JsonSerializationContext context) { - final JsonObject object = new JsonObject(); - writeSid(incomingPhoneNumber.getSid(), object); - writeAccountSid(incomingPhoneNumber.getAccountSid(), object); - writeFriendlyName(incomingPhoneNumber.getFriendlyName(), object); - writePhoneNumber(incomingPhoneNumber.getPhoneNumber(), object); - writeVoiceUrl(incomingPhoneNumber.getVoiceUrl(), object); - writeVoiceMethod(incomingPhoneNumber.getVoiceMethod(), object); - writeVoiceFallbackUrl(incomingPhoneNumber.getVoiceFallbackUrl(), object); - writeVoiceFallbackMethod(incomingPhoneNumber.getVoiceFallbackMethod(), object); - writeStatusCallback(incomingPhoneNumber.getStatusCallback(), object); - writeStatusCallbackMethod(incomingPhoneNumber.getStatusCallbackMethod(), object); - writeVoiceCallerIdLookup(incomingPhoneNumber.hasVoiceCallerIdLookup(), object); - writeVoiceApplicationSid(incomingPhoneNumber.getVoiceApplicationSid(), object); - writeDateCreated(incomingPhoneNumber.getDateCreated(), object); - writeDateUpdated(incomingPhoneNumber.getDateUpdated(), object); - writeSmsUrl(incomingPhoneNumber.getSmsUrl(), object); - writeSmsMethod(incomingPhoneNumber.getSmsMethod(), object); - writeSmsFallbackUrl(incomingPhoneNumber.getSmsFallbackUrl(), object); - writeSmsFallbackMethod(incomingPhoneNumber.getSmsFallbackMethod(), object); - writeSmsApplicationSid(incomingPhoneNumber.getSmsApplicationSid(), object); - writeCapabilities(incomingPhoneNumber.isVoiceCapable(), incomingPhoneNumber.isSmsCapable(), incomingPhoneNumber.isMmsCapable(), incomingPhoneNumber.isFaxCapable(), object); - writeApiVersion(incomingPhoneNumber.getApiVersion(), object); - writeUri(incomingPhoneNumber.getUri(), object); - return object; - } - - private void writeSmsApplicationSid(final Sid smsApplicationSid, final HierarchicalStreamWriter writer) { - writer.startNode("SmsApplicationSid"); - if (smsApplicationSid != null) { - writer.setValue(smsApplicationSid.toString()); - } else { - writer.setValue(null); - } - writer.endNode(); - } - - private void writeSmsApplicationSid(final Sid smsApplicationSid, final JsonObject object) { - if (smsApplicationSid != null) { - object.addProperty("sms_application_sid", smsApplicationSid.toString()); - } else { - object.add("sms_application_sid", JsonNull.INSTANCE); - } - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberListConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberListConverter.java deleted file mode 100644 index 489d7ff8ab..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/IncomingPhoneNumberListConverter.java +++ /dev/null @@ -1,54 +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.mobicents.servlet.restcomm.http.converter; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumber; -import org.mobicents.servlet.restcomm.entities.IncomingPhoneNumberList; - -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class IncomingPhoneNumberListConverter extends AbstractConverter { - public IncomingPhoneNumberListConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return IncomingPhoneNumberList.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final IncomingPhoneNumberList list = (IncomingPhoneNumberList) object; - writer.startNode("IncomingPhoneNumbers"); - for (final IncomingPhoneNumber incomingPhoneNumber : list.getIncomingPhoneNumbers()) { - context.convertAnother(incomingPhoneNumber); - } - writer.endNode(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationListConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationListConverter.java deleted file mode 100644 index 740c397d1a..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationListConverter.java +++ /dev/null @@ -1,54 +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.mobicents.servlet.restcomm.http.converter; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.NotificationList; - -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class NotificationListConverter extends AbstractConverter { - public NotificationListConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return NotificationList.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final NotificationList list = (NotificationList) object; - writer.startNode("Notifications"); - for (final Notification notification : list.getNotifications()) { - context.convertAnother(notification); - } - writer.endNode(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingConverter.java deleted file mode 100644 index 7addc883e9..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingConverter.java +++ /dev/null @@ -1,78 +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.mobicents.servlet.restcomm.http.converter; - -import java.lang.reflect.Type; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Recording; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class RecordingConverter extends AbstractConverter implements JsonSerializer { - public RecordingConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return Recording.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final Recording recording = (Recording) object; - writer.startNode("Recording"); - writeSid(recording.getSid(), writer); - writeDateCreated(recording.getDateCreated(), writer); - writeDateUpdated(recording.getDateUpdated(), writer); - writeAccountSid(recording.getAccountSid(), writer); - writeCallSid(recording.getCallSid(), writer); - writeDuration(recording.getDuration(), writer); - writeApiVersion(recording.getApiVersion(), writer); - writeUri(recording.getUri(), writer); - writer.endNode(); - } - - @Override - public JsonElement serialize(final Recording recording, final Type type, final JsonSerializationContext context) { - final JsonObject object = new JsonObject(); - writeSid(recording.getSid(), object); - writeDateCreated(recording.getDateCreated(), object); - writeDateUpdated(recording.getDateUpdated(), object); - writeAccountSid(recording.getAccountSid(), object); - writeCallSid(recording.getCallSid(), object); - writeDuration(recording.getDuration(), object); - writeApiVersion(recording.getApiVersion(), object); - writeUri(recording.getUri(), object); - return object; - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingListConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingListConverter.java deleted file mode 100644 index 0b740e2d01..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RecordingListConverter.java +++ /dev/null @@ -1,54 +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.mobicents.servlet.restcomm.http.converter; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Recording; -import org.mobicents.servlet.restcomm.entities.RecordingList; - -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class RecordingListConverter extends AbstractConverter { - public RecordingListConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return RecordingList.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final RecordingList list = (RecordingList) object; - writer.startNode("Recordings"); - for (final Recording recording : list.getRecordings()) { - context.convertAnother(recording); - } - writer.endNode(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageListConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageListConverter.java deleted file mode 100644 index ac8e75c81a..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageListConverter.java +++ /dev/null @@ -1,54 +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.mobicents.servlet.restcomm.http.converter; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.SmsMessage; -import org.mobicents.servlet.restcomm.entities.SmsMessageList; - -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class SmsMessageListConverter extends AbstractConverter { - public SmsMessageListConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return SmsMessageList.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final SmsMessageList list = (SmsMessageList) object; - writer.startNode("SMSMessages"); - for (final SmsMessage sms : list.getSmsMessages()) { - context.convertAnother(sms); - } - writer.endNode(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionListConverter.java b/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionListConverter.java deleted file mode 100644 index 74ce122cd0..0000000000 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionListConverter.java +++ /dev/null @@ -1,54 +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.mobicents.servlet.restcomm.http.converter; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Transcription; -import org.mobicents.servlet.restcomm.entities.TranscriptionList; - -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@ThreadSafe -public final class TranscriptionListConverter extends AbstractConverter { - public TranscriptionListConverter(final Configuration configuration) { - super(configuration); - } - - @SuppressWarnings("rawtypes") - @Override - public boolean canConvert(final Class klass) { - return TranscriptionList.class.equals(klass); - } - - @Override - public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final TranscriptionList list = (TranscriptionList) object; - writer.startNode("Transcriptions"); - for (final Transcription transcription : list.getTranscriptions()) { - context.convertAnother(transcription); - } - writer.endNode(); - } -} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AbstractEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AbstractEndpoint.java new file mode 100644 index 0000000000..a2ab9954cd --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AbstractEndpoint.java @@ -0,0 +1,174 @@ +/* + * 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; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; +import java.math.BigInteger; +import java.net.URI; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.util.StringUtils; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author jean.deruelle@telestax.com + */ +@NotThreadSafe +public abstract class AbstractEndpoint { + + private String defaultApiVersion; + protected Configuration configuration; + protected String baseRecordingsPath; + + public AbstractEndpoint() { + super(); + } + + protected void init(final Configuration configuration) { + final String path = configuration.getString("recordings-path"); + baseRecordingsPath = StringUtils.addSuffixIfNotPresent(path, "/"); + defaultApiVersion = configuration.getString("api-version"); + } + + protected String getApiVersion(final MultivaluedMap data) { + String apiVersion = defaultApiVersion; + if (data != null && data.containsKey("ApiVersion")) { + apiVersion = data.getFirst("ApiVersion"); + } + return apiVersion; + } + + protected PhoneNumber getPhoneNumber(final MultivaluedMap data) { + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + PhoneNumber phoneNumber = null; + try { + phoneNumber = phoneNumberUtil.parse(data.getFirst("PhoneNumber"), "US"); + } catch (final NumberParseException ignored) { + } + return phoneNumber; + } + + protected String getMethod(final String name, final MultivaluedMap data) { + String method = "POST"; + if (data.containsKey(name)) { + method = data.getFirst(name); + } + return method; + } + + protected Sid getSid(final String name, final MultivaluedMap data) { + Sid sid = null; + if (data.containsKey(name)) { + sid = new Sid(data.getFirst(name)); + } + return sid; + } + + protected URI getUrl(final String name, final MultivaluedMap data) { + URI uri = null; + if (data.containsKey(name)) { + uri = URI.create(data.getFirst(name)); + } + return uri; + } + + protected Integer getInteger(final String name, final MultivaluedMap data) { + Integer integer = null; + if (data.containsKey(name)) { + integer = new Integer(data.getFirst(name)); + } + return integer; + } + + protected BigInteger getBigInteger(final String name, final MultivaluedMap data) { + BigInteger bigInteger = null; + if (data.containsKey(name)) { + bigInteger = new BigInteger(data.getFirst(name)); + } + return bigInteger; + } + + protected Long getLong(final String name, final MultivaluedMap data) { + Long l = null; + if (data.containsKey(name)) { + l = new Long(data.getFirst(name)); + } + return l; + } + + protected DateTime getDateTime(final String name, final MultivaluedMap data) { + DateTime dateTime = null; + if (data.containsKey(name)) { + dateTime = new DateTime(data.getFirst(name)); + } + return dateTime; + } + + protected Boolean getBoolean(final String name, final MultivaluedMap data) { + Boolean b = null; + if (data.containsKey(name)) { + b = new Boolean(data.getFirst(name)); + } + return b; + } + + protected boolean getHasVoiceCallerIdLookup(final MultivaluedMap data) { + boolean hasVoiceCallerIdLookup = false; + if (data.containsKey("VoiceCallerIdLookup")) { + final String value = data.getFirst("VoiceCallerIdLookup"); + if ("true".equalsIgnoreCase(value)) { + return true; + } + } + return hasVoiceCallerIdLookup; + } + + // A general purpose method to test incoming parameters for meaningful data + protected boolean isEmpty(Object value) { + if (value == null) + return true; + if ( value.equals("") ) + return true; + return false; + } + + // Quick'n'dirty error response building + String buildErrorResponseBody(String message, MediaType type) { + if (!type.equals(MediaType.APPLICATION_XML_TYPE)) { // fallback to JSON if not XML + return "{\"message\":\""+message+"\"}"; + } else { + return "" + message + ""; + } + } + + String buildErrorResponseBody(String message, String error, MediaType type) { + if (!type.equals(MediaType.APPLICATION_XML_TYPE)) { // fallback to JSON if not XML + return "{\"message\":\""+message+"\",\n\"error\":\""+error+"\"}"; + } else { + return "" + message + ""+ error +""; + } + } +} 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 new file mode 100644 index 0000000000..078ce44a13 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsEndpoint.java @@ -0,0 +1,821 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sun.jersey.core.header.LinkHeader; +import com.sun.jersey.core.header.LinkHeader.LinkHeaderBuilder; +import com.sun.jersey.core.util.MultivaluedMapImpl; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.shiro.crypto.hash.Md5Hash; +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.dao.ClientsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.AccountList; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.http.client.rcmlserver.RcmlserverApi; +import org.restcomm.connect.http.client.rcmlserver.RcmlserverNotifications; +import org.restcomm.connect.http.converter.AccountConverter; +import org.restcomm.connect.http.converter.AccountListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.exceptions.InsufficientPermission; +import org.restcomm.connect.http.exceptions.InvalidEmailException; +import org.restcomm.connect.http.exceptions.PasswordTooWeak; +import org.restcomm.connect.http.exceptions.RcmlserverNotifyError; +import org.restcomm.connect.identity.EmailValidator; +import org.restcomm.connect.identity.passwords.PasswordValidator; +import org.restcomm.connect.identity.passwords.PasswordValidatorFactory; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManager; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManagerProvider; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.ws.rs.WebApplicationException; + +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.Response.Status.PRECONDITION_FAILED; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.entities.Account.Status; +import org.restcomm.connect.dao.entities.ProfileAssociation; +import static org.restcomm.connect.http.ProfileEndpoint.PROFILE_REL_TYPE; +import static org.restcomm.connect.http.ProfileEndpoint.TITLE_PARAM; +import org.restcomm.connect.http.exceptionmappers.CustomReasonPhraseType; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +public class AccountsEndpoint extends SecuredEndpoint { + protected Configuration runtimeConfiguration; + protected Configuration rootConfiguration; // top-level configuration element + protected Gson gson; + protected XStream xstream; + protected ClientsDao clientDao; + protected IncomingPhoneNumbersDao incomingPhoneNumbersDao; + private ProfileAssociationsDao profileAssociationsDao; + + private Map statusActionMap; + + + public AccountsEndpoint() { + super(); + } + + // used for testing + public AccountsEndpoint(ServletContext context, HttpServletRequest request) { + super(context,request); + } + + @PostConstruct + void init() { + rootConfiguration = (Configuration) context.getAttribute(Configuration.class.getName()); + runtimeConfiguration = rootConfiguration.subset("runtime-settings"); + super.init(runtimeConfiguration); + clientDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getClientsDao(); + incomingPhoneNumbersDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getIncomingPhoneNumbersDao(); + profileAssociationsDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getProfileAssociationsDao(); + final AccountConverter converter = new AccountConverter(runtimeConfiguration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Account.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new AccountListConverter(runtimeConfiguration)); + xstream.registerConverter(new RestCommResponseConverter(runtimeConfiguration)); + // Make sure there is an authenticated account present when this endpoint is used + } + + private Account createFrom(final Sid accountSid, final MultivaluedMap data, Account parent) throws PasswordTooWeak { + validate(data); + + final DateTime now = DateTime.now(); + final String emailAddress = (data.getFirst("EmailAddress")).toLowerCase(); + + // Issue 108: https://bitbucket.org/telestax/telscale-restcomm/issue/108/account-sid-could-be-a-hash-of-the + final Sid sid = Sid.generate(Sid.Type.ACCOUNT, emailAddress); + Sid organizationSid=null; + + String friendlyName = emailAddress; + if (data.containsKey("FriendlyName")) { + friendlyName = data.getFirst("FriendlyName"); + } + final Account.Type type = Account.Type.FULL; + Account.Status status = Account.Status.ACTIVE; + if (data.containsKey("Status")) { + status = Account.Status.getValueOf(data.getFirst("Status").toLowerCase()); + } + if (data.containsKey("OrganizationSid")) { + Sid orgSid = new Sid(data.getFirst("OrganizationSid")); + // user can add account in same organization + if(!orgSid.equals(parent.getOrganizationSid())){ + //only super admin can add account in organizations other than it belongs to + allowOnlySuperAdmin(); + if(organizationsDao.getOrganization(orgSid) == null){ + throw new IllegalArgumentException("provided OrganizationSid does not exist"); + } + organizationSid = orgSid; + } + } + organizationSid = organizationSid != null ? organizationSid : parent.getOrganizationSid(); + final String password = data.getFirst("Password"); + PasswordValidator validator = PasswordValidatorFactory.createDefault(); + if (!validator.isStrongEnough(password)) + throw new PasswordTooWeak(); + final String authToken = new Md5Hash(password).toString(); + final String role = data.getFirst("Role"); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(getApiVersion(null)).append("/Accounts/").append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + return new Account(sid, now, now, emailAddress, friendlyName, accountSid, type, status, authToken, role, uri, organizationSid); + } + + public LinkHeader composeLink(Sid targetSid, UriInfo info) { + String sid = targetSid.toString(); + URI uri = info.getBaseUriBuilder().path(ProfileJsonEndpoint.class).path(sid).build(); + LinkHeaderBuilder link = LinkHeader.uri(uri).parameter(TITLE_PARAM, "Profiles"); + return link.rel(PROFILE_REL_TYPE).build(); + } + + protected Response getAccount(final String accountSid, final MediaType responseType, UriInfo info) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + Account account = null; + checkPermission("RestComm:Read:Accounts"); + if (Sid.pattern.matcher(accountSid).matches()) { + try { + account = accountsDao.getAccount(new Sid(accountSid)); + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } else { + try { + account = accountsDao.getAccount(accountSid); + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } + + secure(account, "RestComm:Read:Accounts", SecuredType.SECURED_ACCOUNT ); + + if (account == null) { + return status(NOT_FOUND).build(); + } else { + Response.ResponseBuilder ok = Response.ok(); + ProfileAssociation profileAssociationByTargetSid = profileAssociationsDao.getProfileAssociationByTargetSid(accountSid); + if (profileAssociationByTargetSid != null) { + LinkHeader profileLink = composeLink(profileAssociationByTargetSid.getProfileSid(), info); + ok.header(ProfileEndpoint.LINK_HEADER, profileLink.toString()); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(account); + return ok.type(APPLICATION_XML).entity(xstream.toXML(response)).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok.type(APPLICATION_JSON).entity(gson.toJson(account)).build(); + } else { + return null; + } + } + } + + // Account removal disabled as per https://github.com/RestComm/Restcomm-Connect/issues/1270 + /* + protected Response deleteAccount(final String operatedSid) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + checkPermission("RestComm:Delete:Accounts"); + // what if effectiveAccount is null ?? - no need to check since we checkAuthenticatedAccount() in AccountsEndoint.init() + final Sid accountSid = userIdentityContext.getEffectiveAccount().getSid(); + final Sid sidToBeRemoved = new Sid(operatedSid); + + Account removedAccount = accountsDao.getAccount(sidToBeRemoved); + secure(removedAccount, "RestComm:Delete:Accounts", SecuredType.SECURED_ACCOUNT); + // Prevent removal of Administrator account + if (operatedSid.equalsIgnoreCase(accountSid.toString())) + return status(BAD_REQUEST).build(); + + if (accountsDao.getAccount(sidToBeRemoved) == null) + return status(NOT_FOUND).build(); + + // the whole tree of sub-accounts has to be removed as well + List removedAccounts = accountsDao.getSubAccountSidsRecursive(sidToBeRemoved); + if (removedAccounts != null && !removedAccounts.isEmpty()) { + int i = removedAccounts.size(); // is is the count of accounts left to process + while (i > 0) { + i --; + String removedSid = removedAccounts.get(i); + try { + removeSingleAccount(removedSid); + } catch (Exception e) { + // if anything bad happens, log the error and continue removing the rest of the accounts. + logger.error("Failed removing (child) account '" + removedSid + "'"); + } + } + } + // remove the parent account too + removeSingleAccount(operatedSid); + + return ok().build(); + }*/ + + /* + protected Response deleteAccount(final String operatedSid) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + checkPermission("RestComm:Delete:Accounts"); + // what if effectiveAccount is null ?? - no need to check since we checkAuthenticatedAccount() in AccountsEndoint.init() + final Sid accountSid = userIdentityContext.getEffectiveAccount().getSid(); + final Sid sidToBeRemoved = new Sid(operatedSid); + + Account removedAccount = accountsDao.getAccount(sidToBeRemoved); + secure(removedAccount, "RestComm:Delete:Accounts", SecuredType.SECURED_ACCOUNT); + // Prevent removal of Administrator account + if (operatedSid.equalsIgnoreCase(accountSid.toString())) + return status(BAD_REQUEST).build(); + + if (accountsDao.getAccount(sidToBeRemoved) == null) + return status(NOT_FOUND).build(); + + accountsDao.removeAccount(sidToBeRemoved); + + // Remove its SIP client account + clientDao.removeClients(sidToBeRemoved); + + return ok().build(); + } + */ + /** + * Removes all dependent resources of an account. Some resources like + * CDRs are excluded. + * + * @param sid + */ + private void removeAccoundDependencies(Sid sid) { + logger.debug("removing accoutn dependencies"); + DaoManager daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + // remove dependency entities first and dependent entities last. Also, do safer operation first (as a secondary rule) + daoManager.getAnnouncementsDao().removeAnnouncements(sid); + daoManager.getNotificationsDao().removeNotifications(sid); + daoManager.getShortCodesDao().removeShortCodes(sid); + daoManager.getOutgoingCallerIdsDao().removeOutgoingCallerIds(sid); + daoManager.getTranscriptionsDao().removeTranscriptions(sid); + daoManager.getRecordingsDao().removeRecordings(sid); + daoManager.getApplicationsDao().removeApplications(sid); + removeIncomingPhoneNumbers(sid,daoManager.getIncomingPhoneNumbersDao()); + daoManager.getClientsDao().removeClients(sid); + profileAssociationsDao.deleteProfileAssociationByTargetSid(sid.toString()); + } + + /** + * Removes incoming phone numbers that belong to an account from the database. + * For provided numbers the provider is also contacted to get them released. + * + * @param accountSid + * @param dao + */ + private void removeIncomingPhoneNumbers(Sid accountSid, IncomingPhoneNumbersDao dao) { + List numbers = dao.getIncomingPhoneNumbers(accountSid); + if (numbers != null && numbers.size() > 0) { + // manager is retrieved in a lazy way. If any number needs it, it will be first retrieved + // from the servlet context. If not there it will be created, stored in context and returned. + boolean managerQueried = false; + PhoneNumberProvisioningManager manager = null; + for (IncomingPhoneNumber number : numbers) { + // if this is not just a SIP number try to release it by contacting the provider + if (number.isPureSip() == null || !number.isPureSip()) { + if ( ! managerQueried ) + manager = new PhoneNumberProvisioningManagerProvider(rootConfiguration,context).get(); // try to retrieve/build manager only once + if (manager != null) { + try { + if (! manager.cancelNumber(IncomingPhoneNumbersEndpoint.convertIncomingPhoneNumbertoPhoneNumber(number)) ) { + logger.error("Number cancelation failed for provided number '" + number.getPhoneNumber()+"'. Number entity " + number.getSid() + " will stay in database"); + } else { + dao.removeIncomingPhoneNumber(number.getSid()); + } + } catch (Exception e) { + logger.error("Number cancelation failed for provided number '" + number.getPhoneNumber()+"'",e); + } + } + else + logger.error("Number cancelation failed for provided number '" + number.getPhoneNumber()+"'. Provisioning Manager was null. "+"Number entity " + number.getSid() + " will stay in database"); + } else { + // pureSIP numbers only to be removed from database. No need to contact provider + dao.removeIncomingPhoneNumber(number.getSid()); + } + } + } + } + + + + protected Response getAccounts(final UriInfo info, final MediaType responseType) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + checkPermission("RestComm:Read:Accounts"); + final Account account = userIdentityContext.getEffectiveAccount(); + if (account == null) { + return status(NOT_FOUND).build(); + } else { + final List accounts = new ArrayList(); + + if (info == null) { + accounts.addAll(accountsDao.getChildAccounts(account.getSid())); + } else { + String organizationSid = info.getQueryParameters().getFirst("OrganizationSid"); + String domainName = info.getQueryParameters().getFirst("DomainName"); + + if(organizationSid != null && !(organizationSid.trim().isEmpty())){ + allowOnlySuperAdmin(); + accounts.addAll(accountsDao.getAccountsByOrganization(new Sid(organizationSid))); + } else if(domainName != null && !(domainName.trim().isEmpty())){ + allowOnlySuperAdmin(); + Organization organization = organizationsDao.getOrganizationByDomainName(domainName); + if(organization == null){ + return status(NOT_FOUND).build(); + } + accounts.addAll(accountsDao.getAccountsByOrganization(organization.getSid())); + } else { + accounts.addAll(accountsDao.getChildAccounts(account.getSid())); + } + } + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new AccountList(accounts)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(accounts), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response putAccount(final MultivaluedMap data, final MediaType responseType) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + checkPermission("RestComm:Create:Accounts"); + // check account level depth. If we're already at third level no sub-accounts are allowed to be created + List accountLineage = userIdentityContext.getEffectiveAccountLineage(); + if (accountLineage.size() >= 2) { + // there are already 2+1=3 account levels. Sub-accounts at 4th level are not allowed + return status(BAD_REQUEST).entity(buildErrorResponseBody("This account is not allowed to have sub-accounts",responseType)).type(responseType).build(); + } + + // what if effectiveAccount is null ?? - no need to check since we checkAuthenticatedAccount() in AccountsEndoint.init() + final Sid sid = userIdentityContext.getEffectiveAccount().getSid(); + + ExtensionController ec = ExtensionController.getInstance(); + ApiRequest apiRequest = new ApiRequest(sid.toString(), data, ApiRequest.Type.CREATE_SUBACCOUNT); + + if (executePreApiAction(apiRequest)) { + final Account parent = accountsDao.getAccount(sid); + Account account = null; + try { + account = createFrom(sid, data, parent); + } catch (IllegalArgumentException illegalArgumentException) { + return status(BAD_REQUEST).entity(illegalArgumentException.getMessage()).build(); + }catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } catch (PasswordTooWeak passwordTooWeak) { + return status(BAD_REQUEST).entity(buildErrorResponseBody("Password too weak",responseType)).type(responseType).build(); + } + + // If Account already exists don't add it again + /* + Account creation rules: + - either be Administrator or have the following permission: RestComm:Create:Accounts + - only Administrators can choose a role for newly created accounts. Normal users will create accounts with the same role as their own. + */ + if (accountsDao.getAccount(account.getSid()) == null && !account.getEmailAddress().equalsIgnoreCase("administrator@company.com")) { + if (parent.getStatus().equals(Account.Status.ACTIVE) && isSecuredByPermission("RestComm:Create:Accounts")) { + if (!hasAccountRole(getAdministratorRole()) || !data.containsKey("Role")) { + account = account.setRole(parent.getRole()); + } + accountsDao.addAccount(account); + + // Create default SIP client data + MultivaluedMap clientData = new MultivaluedMapImpl(); + String username = data.getFirst("EmailAddress").split("@")[0]; + clientData.add("Login", username); + clientData.add("Password", data.getFirst("Password")); + clientData.add("FriendlyName", account.getFriendlyName()); + clientData.add("AccountSid", account.getSid().toString()); + Client client = clientDao.getClient(clientData.getFirst("Login"), account.getOrganizationSid()); + if (client == null) { + client = createClientFrom(account.getSid(), clientData); + clientDao.addClient(client); + } + } else { + throw new InsufficientPermission(); + } + } else { + return status(CONFLICT).entity("The email address used for the new account is already in use.").build(); + } + + executePostApiAction(apiRequest); + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(account), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(account); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } else { + if (logger.isDebugEnabled()) { + final String errMsg = "Creation of sub-accounts is not Allowed"; + logger.debug(errMsg); + } + executePostApiAction(apiRequest); + String errMsg = "Creation of sub-accounts is not Allowed"; + return status(Response.Status.FORBIDDEN).entity(errMsg).build(); + } + } + + private Client createClientFrom(final Sid accountSid, final MultivaluedMap data) { + final Client.Builder builder = Client.builder(); + final Sid sid = Sid.generate(Sid.Type.CLIENT); + + // TODO: need to encrypt this password because it's same with Account + // password. + // Don't implement now. Opened another issue for it. + // String password = new Md5Hash(data.getFirst("Password")).toString(); + String password = data.getFirst("Password"); + + builder.setSid(sid); + builder.setAccountSid(accountSid); + builder.setApiVersion(getApiVersion(data)); + builder.setLogin(data.getFirst("Login")); + builder.setPassword(password); + builder.setFriendlyName(data.getFirst("FriendlyName")); + builder.setStatus(Client.ENABLED); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Clients/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + /** + * Fills an account entity object with values supplied from an http request + * + * @param account + * @param data + * @return a new instance with given account,and overriden fields from data + */ + private Account prepareAccountForUpdate(final Account account, final MultivaluedMap data) { + Account.Builder accBuilder = Account.builder(); + //copy full incoming account, and let override happen + //in a separate instance later + accBuilder.copy(account); + + + if (data.containsKey("Status")) { + Account.Status newStatus = Account.Status.getValueOf(data.getFirst("Status").toLowerCase()); + accBuilder.setStatus(newStatus); + } + if (data.containsKey("FriendlyName")) { + accBuilder.setFriendlyName(data.getFirst("FriendlyName")); + } + if (data.containsKey("Password")) { + // if this is a reset-password operation, we also need to set the account status to active + if (account.getStatus() == Account.Status.UNINITIALIZED) { + accBuilder.setStatus(Account.Status.ACTIVE); + } + + String password = data.getFirst("Password"); + PasswordValidator validator = PasswordValidatorFactory.createDefault(); + if (!validator.isStrongEnough(password)) { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.BAD_REQUEST, "Password too weak"); + throw new WebApplicationException(status(stat).build()); + } + final String hash = new Md5Hash(data.getFirst("Password")).toString(); + accBuilder.setAuthToken(hash); + } + if (data.containsKey("Role")) { + // Only allow role change for administrators. Multitenancy checks will take care of restricting the modification scope to sub-accounts. + if (userIdentityContext.getEffectiveAccountRoles().contains(getAdministratorRole())) { + accBuilder.setRole(data.getFirst("Role")); + } else { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.FORBIDDEN, "Only Administrator allowed"); + throw new WebApplicationException(status(stat).build()); + } + } + if (data.containsKey("EmailAddress")) { + String newEmailAddress = data.getFirst("EmailAddress").toLowerCase(); + if (!EmailValidator.isValidEmailFormat(newEmailAddress)) { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.BAD_REQUEST, "Not allowed email address format"); + throw new WebApplicationException(status(stat).build()); + } + if (accountsDao.getAccount(newEmailAddress) != null) { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.CONFLICT, "This email address was already taken. Please, choose a different email address and try again."); + throw new WebApplicationException(status(stat).build()); + } + accBuilder.setEmailAddress(newEmailAddress); + } + + return accBuilder.build(); + } + + /** + * update SIP client of the corresponding Account.Password and FriendlyName fields are synched. + */ + private void updateLinkedClient(Account account, MultivaluedMap data) { + logger.debug("checking linked client"); + String email = account.getEmailAddress(); + if (email != null && !email.equals("")) { + logger.debug("account email is valid"); + String username = email.split("@")[0]; + Client client = clientDao.getClient(username, account.getOrganizationSid()); + if (client != null) { + logger.debug("client found"); + // TODO: need to encrypt this password because it's + // same with Account password. + // Don't implement now. Opened another issue for it. + if (data.containsKey("Password")) { + // Md5Hash(data.getFirst("Password")).toString(); + logger.debug("password changed"); + String password = data.getFirst("Password"); + client = client.setPassword(password); + } + + if (data.containsKey("FriendlyName")) { + logger.debug("friendlyname changed"); + client = client.setFriendlyName(data.getFirst("FriendlyName")); + } + logger.debug("updating linked client"); + clientDao.updateClient(client); + } + } + } + + protected Response updateAccount(final String identifier, final MultivaluedMap data, + final MediaType responseType) { + // First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO + // operations + checkPermission("RestComm:Modify:Accounts"); + Account account = getOperatingAccount(identifier); + + if (account == null) { + return status(NOT_FOUND).build(); + } else { + // since the operated account exists, first thing to do is make sure we have access + secure(account, "RestComm:Modify:Accounts", SecuredType.SECURED_ACCOUNT); + + // if the account is already CLOSED, no updates are allowed + if (account.getStatus() == Account.Status.CLOSED) { + // If the account is CLOSED, no updates are allowed. Return a BAD_REQUEST status code. + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.BAD_REQUEST, "Account is closed"); + throw new WebApplicationException(status(stat).build()); + } + + Account modifiedAccount; + modifiedAccount = prepareAccountForUpdate(account, data); + + // we are modifying status + if (modifiedAccount.getStatus() != null && + account.getStatus() != modifiedAccount.getStatus()) { + switchAccountStatusTree(modifiedAccount); + } + + //update client only if friendlyname or password was changed + if (data.containsKey("Password") || + data.containsKey("FriendlyName") ) { + updateLinkedClient(account, data); + } + accountsDao.updateAccount(modifiedAccount); + + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(modifiedAccount), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(modifiedAccount); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } + + private Account getOperatingAccount (String identifier) { + Sid sid = null; + Account account = null; + try { + sid = new Sid(identifier); + account = accountsDao.getAccount(sid); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Exception trying to get account using SID. Seems we have email as identifier"); + } + } + if (account == null) { + account = accountsDao.getAccount(identifier); + } + return account; + } + + private Organization getOrganization(final MultivaluedMap data) { + Organization organization = null; + String organizationId = null; + + if (data.containsKey("Organization")) { + organizationId = data.getFirst("Organization"); + } else { + return null; + } + + if (Sid.pattern.matcher(organizationId).matches()) { + //Attempt to get Organization by SID + organization = organizationsDao.getOrganization(new Sid(organizationId)); + return organization; + } else { + //Attempt to get Organization by domain name + organization = organizationsDao.getOrganizationByDomainName(organizationId); + return organization; + } + } + + protected Response migrateAccountOrganization(final String identifier, final MultivaluedMap data, + final MediaType responseType) { + + Organization organization = getOrganization(data); + //Validation 2 - Check if data contains Organization (either SID or domain name) + if (organization == null) { + return status(PRECONDITION_FAILED).entity("Missing Organization SID or Domain Name").build(); + } + + Account operatingAccount = getOperatingAccount(identifier); + + //Validation 3 - Operating Account shouldn't be null; + if (operatingAccount == null) { + return status(NOT_FOUND).build(); + } + + //Validation 4 - Only direct child of super admin account can be migrated to a new organization + if (!isDirectChildOfAccount(userIdentityContext.getEffectiveAccount(), operatingAccount)) { + return status(BAD_REQUEST).build(); + } + + //Validation 5 - Check if Account already in the requested Organization + if (operatingAccount.getOrganizationSid().equals(organization.getSid())) { + return status(BAD_REQUEST).entity("Account already in the requested Organization").build(); + } + + //Update Account for the new Organization + Account modifiedAccount = operatingAccount.setOrganizationSid(organization.getSid()); + accountsDao.updateAccount(modifiedAccount); + + if (logger.isDebugEnabled()) { + String msg = String.format("Parent Account %s migrated to Organization %s", modifiedAccount.getSid(), organization.getSid()); + logger.debug(msg); + } + + //Update Child accounts and their numbers + List childAccounts = accountsDao.getChildAccounts(operatingAccount.getSid()); + for (Account child : childAccounts) { + if (!child.getOrganizationSid().equals(organization.getSid())) { + Account modifiedChildAccount = child.setOrganizationSid(organization.getSid()); + accountsDao.updateAccount(modifiedChildAccount); + if (logger.isDebugEnabled()) { + String msg = String.format("Child Account %s from Parent Account %s, migrated to Organization %s", modifiedChildAccount.getSid(), modifiedAccount.getSid(), organization.getSid()); + logger.debug(msg); + } + } + } + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(modifiedAccount), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(modifiedAccount); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + + private void sendRVDStatusNotification(Account updatedAccount) { + logger.debug("sendRVDStatusNotification"); + // set rcmlserverApi in case we need to also notify the application sever (RVD) + RestcommConfiguration rcommConfiguration = RestcommConfiguration.getInstance(); + RcmlserverConfigurationSet config = rcommConfiguration.getRcmlserver(); + if (config != null && config.getNotify()) { + logger.debug("notification enabled"); + // first send account removal notification to RVD now that the applications of the account still exist + RcmlserverApi rcmlServerApi = new RcmlserverApi(rcommConfiguration.getMain(), rcommConfiguration.getRcmlserver()); + RcmlserverNotifications notifications = new RcmlserverNotifications(); + notifications.add(rcmlServerApi.buildAccountStatusNotification(updatedAccount)); + Account notifier = userIdentityContext.getEffectiveAccount(); + rcmlServerApi.transmitNotifications(notifications, notifier.getSid().toString(), notifier.getAuthToken()); + } + } + + + /** + * Switches an account status at dao level. + * + * If status is CLSOED, Removes all resources belonging to an account. + * + * If rcmlServerApi is not null it will + * also send account-removal notifications to the rcmlserver + * + * @param account + */ + private void switchAccountStatus(Account account, Account.Status status) { + if (logger.isDebugEnabled()) { + logger.debug("Switching status for account:" + account.getSid() + ",status:" + status); + } + switch (status) { + case CLOSED: + sendRVDStatusNotification(account); + // then proceed to dependency removal + removeAccoundDependencies(account.getSid()); + break; + default: + break; + + } + // finally, set and persist account status + account = account.setStatus(status); + accountsDao.updateAccount(account); + } + + /** + * Switches status of account along with all its children (the whole tree). + * + * @param parentAccount + */ + private void switchAccountStatusTree(Account parentAccount) { + logger.debug("Status transition requested"); + // transition child accounts + List subAccountsToSwitch = accountsDao.getSubAccountSidsRecursive(parentAccount.getSid()); + if (subAccountsToSwitch != null && !subAccountsToSwitch.isEmpty()) { + int i = subAccountsToSwitch.size(); // is is the count of accounts left to process + // we iterate backwards to handle child accounts first, parent accounts next + while (i > 0) { + i --; + String removedSid = subAccountsToSwitch.get(i); + try { + Account subAccount = accountsDao.getAccount(new Sid(removedSid)); + switchAccountStatus(subAccount, parentAccount.getStatus()); + } catch (Exception e) { + // if anything bad happens, log the error and continue removing the rest of the accounts. + logger.error("Failed switching status (child) account '" + removedSid + "'"); + } + } + } + // switch parent account too + switchAccountStatus(parentAccount, parentAccount.getStatus()); + } + + private void validate(final MultivaluedMap data) throws NullPointerException { + if (!data.containsKey("EmailAddress")) { + throw new NullPointerException("Email address can not be null."); + } else if (!data.containsKey("Password")) { + throw new NullPointerException("Password can not be null."); + } + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsJsonEndpoint.java new file mode 100644 index 0000000000..e6eefe9592 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsJsonEndpoint.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.http; + +import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.OPTIONS; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts.json") +@ThreadSafe +public final class AccountsJsonEndpoint extends AccountsEndpoint { + public AccountsJsonEndpoint() { + super(); + } + + @Path("/{accountSid}") + @GET + public Response getAccountAsJson(@PathParam("accountSid") final String accountSid, + @Context UriInfo info) { + return getAccount(accountSid, APPLICATION_JSON_TYPE, info); + } + + @Path("/{accountSid}") + @OPTIONS + public Response optionsAccount(@PathParam("accountSid") final String accountSid) { + // no authentication here since this is a pre-flight request + return Response.ok().build(); + } + + @GET + public Response getAccounts(@Context UriInfo info) { + return getAccounts(info, APPLICATION_JSON_TYPE); + } + + /* disabled as #1270 + @Path("/{sid}.json") + @DELETE + public Response deleteAccountAsJson(@PathParam("sid") final String sid) { + return deleteAccount(sid); + } + */ + + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + public Response putAccount(final MultivaluedMap data) { + return putAccount(data, APPLICATION_JSON_TYPE); + } + + //The {accountSid} could be the email address of the account we need to update. Later we check if this is SID or EMAIL + @Path("/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + public Response updateAccountAsJsonPost(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return updateAccount(accountSid, data, APPLICATION_JSON_TYPE); + } + + //The {accountSid} could be the email address of the account we need to update. Later we check if this is SID or EMAIL + @Path("/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @PUT + public Response updateAccountAsJsonPut(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return updateAccount(accountSid, data, APPLICATION_JSON_TYPE); + } + + + @Path("/migrate/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response migrateAccount(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return migrateAccountOrganization(accountSid, data, APPLICATION_JSON_TYPE); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsXmlEndpoint.java new file mode 100644 index 0000000000..46cf8c1f99 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsXmlEndpoint.java @@ -0,0 +1,102 @@ +/* + * 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; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts") +@ThreadSafe +public final class AccountsXmlEndpoint extends AccountsEndpoint { + public AccountsXmlEndpoint() { + super(); + } + + /* + @Path("/{sid}") + @DELETE + public Response deleteAccountAsXml(@PathParam("sid") final String sid) { + return deleteAccount(sid); + } + */ + + @Path("/{accountSid}") + @GET + public Response getAccountAsXml(@PathParam("accountSid") final String accountSid, + @Context UriInfo info) { + return getAccount(accountSid, APPLICATION_XML_TYPE, info); + } + + @GET + public Response getAccounts(@Context UriInfo info) { + return getAccounts(info, APPLICATION_XML_TYPE); + } + + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + public Response putAccount(final MultivaluedMap data) { + return putAccount(data, APPLICATION_XML_TYPE); + } + + //The {accountSid} could be the email address of the account we need to update. Later we check if this is SID or EMAIL + @Path("/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + public Response updateAccountAsXmlPost(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return updateAccount(accountSid, data, APPLICATION_XML_TYPE); + } + + //The {accountSid} could be the email address of the account we need to update. Later we check if this is SID or EMAIL + @Path("/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @PUT + public Response updateAccountAsXmlPut(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return updateAccount(accountSid, data, APPLICATION_XML_TYPE); + } + + @Path("/migrate/{accountSid}") + @Consumes(APPLICATION_FORM_URLENCODED) + @POST + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response migrateAccount(@PathParam("accoutSid") final String accountSid, final MultivaluedMap data) { + return migrateAccountOrganization(accountSid, data, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsEndpoint.java similarity index 75% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsEndpoint.java index d1e538290d..42bde44e90 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsEndpoint.java @@ -1,45 +1,5 @@ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; -import static akka.pattern.Patterns.ask; -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.ok; -import static javax.ws.rs.core.Response.status; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; - -import java.net.URI; -import java.util.concurrent.TimeUnit; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; - -import org.apache.commons.configuration.Configuration; -import org.apache.http.annotation.NotThreadSafe; -import org.apache.log4j.Logger; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.cache.DiskCache; -import org.mobicents.servlet.restcomm.cache.DiskCacheRequest; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Announcement; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.AnnouncementConverter; -import org.mobicents.servlet.restcomm.http.converter.AnnouncementListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerRequest; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerResponse; - -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.Duration; import akka.actor.Actor; import akka.actor.ActorRef; import akka.actor.ActorSystem; @@ -47,29 +7,58 @@ import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; import akka.util.Timeout; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.cache.DiskCacheFactory; +import org.restcomm.connect.commons.cache.DiskCacheRequest; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Announcement; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.AnnouncementConverter; +import org.restcomm.connect.http.converter.AnnouncementListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; +import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import static akka.pattern.Patterns.ask; +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.ok; /** * @author George Vagenas */ -@NotThreadSafe -public abstract class AnnouncementsEndpoint extends AbstractEndpoint { +public abstract class AnnouncementsEndpoint extends SecuredEndpoint { private static Logger logger = Logger.getLogger(AnnouncementsEndpoint.class); @Context protected ServletContext context; protected Configuration configuration; protected Configuration runtime; - protected ActorSystem system; protected ActorRef synthesizer; protected ActorRef cache; protected Gson gson; protected XStream xstream; - protected AccountsDao dao; private URI uri; + private ActorSystem system; public AnnouncementsEndpoint() { super(); @@ -77,8 +66,6 @@ public AnnouncementsEndpoint() { @PostConstruct public void init() { - final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); - dao = storage.getAccountsDao(); system = (ActorSystem) context.getAttribute(ActorSystem.class.getName()); configuration = (Configuration) context.getAttribute(Configuration.class.getName()); Configuration ttsConfiguration = configuration.subset("speech-synthesizer"); @@ -99,11 +86,7 @@ public void init() { public Response putAnnouncement(final String accountSid, final MultivaluedMap data, final MediaType responseType) throws Exception { - try { - secure(dao.getAccount(accountSid), "RestComm:Create:Announcements"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + secure(accountsDao.getAccount(accountSid), "RestComm:Create:Announcements"); if(cache == null) createCacheActor(accountSid); @@ -133,7 +116,9 @@ private void createCacheActor(final String accountId) { } private void precache(final String text, final String gender, final String language) throws Exception { - logger.info("Synthesizing announcement"); + if(logger.isInfoEnabled()){ + logger.info("Synthesizing announcement"); + } final SpeechSynthesizerRequest synthesize = new SpeechSynthesizerRequest(gender, language, text); Timeout expires = new Timeout(Duration.create(6000, TimeUnit.SECONDS)); Future future = (Future) ask(synthesizer, synthesize, expires); @@ -143,7 +128,9 @@ private void precache(final String text, final String gender, final String langu uri = response.get(); } final DiskCacheRequest request = new DiskCacheRequest(uri); - logger.info("Caching announcement"); + if(logger.isInfoEnabled()){ + logger.info("Caching announcement"); + } cache.tell(request, null); } @@ -161,7 +148,9 @@ private Announcement createFrom(String accountSid, MultivaluedMapGeorge Vagenas diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsXmlEndpoint.java similarity index 85% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsXmlEndpoint.java index cd57d04bde..f868275c13 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AnnouncementsXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AnnouncementsXmlEndpoint.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -7,7 +7,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author George Vagenas diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsEndpoint.java new file mode 100644 index 0000000000..2bf7302251 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsEndpoint.java @@ -0,0 +1,256 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.ApplicationsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.dao.entities.ApplicationList; +import org.restcomm.connect.dao.entities.ApplicationNumberSummary; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.ApplicationConverter; +import org.restcomm.connect.http.converter.ApplicationListConverter; +import org.restcomm.connect.http.converter.ApplicationNumberSummaryConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.net.URI; +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.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +/** + * @author guilherme.jansen@telestax.com + */ +@NotThreadSafe +public class ApplicationsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected ApplicationsDao dao; + protected Gson gson; + protected XStream xstream; + protected AccountsDao accountsDao; + + public ApplicationsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + dao = storage.getApplicationsDao(); + accountsDao = storage.getAccountsDao(); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + final ApplicationConverter converter = new ApplicationConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Application.class, converter); + builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); // if custom converter is not provided, rename camelCase to camel_case. Needed for serializing ApplicationNumberSummary and hopefully other entities too at some point. + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new ApplicationListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(new ApplicationNumberSummaryConverter()); + xstream.alias("Number",ApplicationNumberSummary.class); + } + + private Application createFrom(final Sid accountSid, final MultivaluedMap data) { + final Application.Builder builder = Application.builder(); + final Sid sid = Sid.generate(Sid.Type.APPLICATION); + builder.setSid(sid); + builder.setFriendlyName(data.getFirst("FriendlyName")); + builder.setAccountSid(accountSid); + builder.setApiVersion(getApiVersion(data)); + builder.setHasVoiceCallerIdLookup(new Boolean(data.getFirst("VoiceCallerIdLookup"))); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Applications/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + builder.setRcmlUrl(getUrl("RcmlUrl", data)); + if (data.containsKey("Kind")) { + builder.setKind(Application.Kind.getValueOf(data.getFirst("Kind"))); + } + return builder.build(); + } + + protected Response getApplication(final String accountSid, final String sid, final MediaType responseType) { + Account account; + secure(account = accountsDao.getAccount(accountSid), "RestComm:Read:Applications"); + Application application = null; + if (Sid.pattern.matcher(sid).matches()) { + application = dao.getApplication(new Sid(sid)); + } /*else { + // disabled support for application retrieval based on FriendlyName. It makes no sense to have it if friendly-name based application uniqueness is no longer supported either. + + try { + // Once not a valid sid, search using the parameter as name + String name = URLDecoder.decode(String.valueOf(sid), "UTF-8"); + application = dao.getApplication(name); + } catch (UnsupportedEncodingException e) { + return status(BAD_REQUEST).entity(e.getMessage()).build(); + } + }*/ + if (application == null) { + return status(NOT_FOUND).build(); + } else { + secure(account, application.getAccountSid(), SecuredType.SECURED_APP); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(application); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(application), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getApplications(final String accountSid, final MediaType responseType, UriInfo uriInfo) { + Account account; + account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Read:Applications", SecuredType.SECURED_APP); + // shall we also return number information with the application ? + boolean includeNumbers = false; + String tmp = uriInfo.getQueryParameters().getFirst("includeNumbers"); + if (tmp != null && tmp.equalsIgnoreCase("true")) + includeNumbers = true; + + final List applications = dao.getApplicationsWithNumbers(account.getSid()); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new ApplicationList(applications)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(applications), APPLICATION_JSON).build(); + } else { + return null; + } + } + + public Response putApplication(final String accountSid, final MultivaluedMap data, + final MediaType responseType) { + Account account; + account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Create:Applications", SecuredType.SECURED_APP); + try { + validate(data); + } catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + +// Application application = dao.getApplication(data.getFirst("FriendlyName")); +// if (application == null) { +// application = createFrom(new Sid(accountSid), data); +// dao.addApplication(application); +// } else if (!application.getAccountSid().toString().equals(account.getSid().toString())) { +// return status(CONFLICT) +// .entity("A application with the same name was already created by another account. Please, choose a different name and try again.") +// .build(); +// } + + // application uniqueness now relies only on application SID. No checks on the FriendlyName will be done. + Application application = createFrom(new Sid(accountSid), data); + dao.addApplication(application); + + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(application); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(application), APPLICATION_JSON).build(); + } else { + return null; + } + } + + private void validate(final MultivaluedMap data) throws RuntimeException { + if (!data.containsKey("FriendlyName")) { + throw new NullPointerException("Friendly name can not be null."); + } + } + + protected Response updateApplication(final String accountSid, final String sid, final MultivaluedMap data, + final MediaType responseType) { + Account account; + secure(account = accountsDao.getAccount(accountSid), "RestComm:Modify:Applications"); + final Application application = dao.getApplication(new Sid(sid)); + if (application == null) { + return status(NOT_FOUND).build(); + } else { + secure(account, application.getAccountSid(), SecuredType.SECURED_APP); + final Application applicationUpdate = update(application, data); + dao.updateApplication(applicationUpdate); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(applicationUpdate); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(applicationUpdate), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private Application update(final Application application, final MultivaluedMap data) { + Application result = application; + if (data.containsKey("FriendlyName")) { + result = result.setFriendlyName(data.getFirst("FriendlyName")); + } + if (data.containsKey("VoiceCallerIdLookup")) { + result = result.setVoiceCallerIdLookup(new Boolean(data.getFirst("VoiceCallerIdLookup"))); + } + if (data.containsKey("RcmlUrl")) { + result = result.setRcmlUrl(getUrl("RcmlUrl", data)); + } + if (data.containsKey("Kind")) { + result = result.setKind(Application.Kind.getValueOf(data.getFirst("Kind"))); + } + return result; + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsJsonEndpoint.java new file mode 100644 index 0000000000..5cc44c423c --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsJsonEndpoint.java @@ -0,0 +1,56 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author guilherme.jansen@telestax.com + */ +@Path("/Accounts/{accountSid}/Applications.json") +@ThreadSafe +public class ApplicationsJsonEndpoint extends ApplicationsEndpoint { + public ApplicationsJsonEndpoint() { + super(); + } + + @GET + public Response getApplications(@PathParam("accountSid") final String accountSid, @Context UriInfo uriInfo) { + return getApplications(accountSid, APPLICATION_JSON_TYPE, uriInfo ); + } + + @POST + public Response putApplication(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return putApplication(accountSid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsXmlEndpoint.java new file mode 100644 index 0000000000..098eb4bb89 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ApplicationsXmlEndpoint.java @@ -0,0 +1,127 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2015, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static javax.ws.rs.core.Response.ok; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author guilherme.jansen@telestax.com + */ +@Path("/Accounts/{accountSid}/Applications") +@ThreadSafe +public class ApplicationsXmlEndpoint extends ApplicationsEndpoint { + public ApplicationsXmlEndpoint() { + super(); + } + + private Response deleteApplication(final String accountSid, final String sid) { + Account operatedAccount = accountsDao.getAccount(new Sid(accountSid)); + secure(operatedAccount, "RestComm:Modify:Applications", SecuredType.SECURED_APP); + Application application = dao.getApplication(new Sid(sid)); + if (application != null) { + secure(operatedAccount, application.getAccountSid(), SecuredType.SECURED_APP); + } + dao.removeApplication(new Sid(sid)); + return ok().build(); + } + + @GET + public Response getApplications(@PathParam("accountSid") final String accountSid, @Context UriInfo uriInfo) { + return getApplications(accountSid, APPLICATION_XML_TYPE, uriInfo ); + } + + @Path("/{sid}") + @GET + public Response getApplicationAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getApplication(accountSid, sid, APPLICATION_XML_TYPE); + } + + @Path("/{sid}.json") + @GET + public Response getApplicationAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getApplication(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @POST + public Response putApplication(@PathParam("accountSid") String accountSid, final MultivaluedMap data) { + return putApplication(accountSid, data, APPLICATION_XML_TYPE); + } + + @Path("/{sid}.json") + @POST + public Response updateApplicationAsJsonPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateApplication(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @POST + public Response updateApplicationAsXmlPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateApplication(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @Path("/{sid}.json") + @PUT + public Response updateApplicationAsJsonPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateApplication(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @PUT + public Response updateApplicationAsXmlPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateApplication(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @Path("/{sid}.json") + @DELETE + public Response deleteApplicationAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return deleteApplication(accountSid, sid); + } + + @Path("/{sid}") + @DELETE + public Response deleteApplicationAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return deleteApplication(accountSid, sid); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersEndpoint.java similarity index 80% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersEndpoint.java index 68bcac8138..9b609b2fa4 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersEndpoint.java @@ -17,56 +17,45 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; - -import static javax.ws.rs.core.Response.ok; -import static javax.ws.rs.core.Response.status; -import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; +package org.restcomm.connect.http; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; - import javax.annotation.PostConstruct; import javax.servlet.ServletContext; -import javax.servlet.sip.SipServlet; -import javax.servlet.sip.SipURI; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; - +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumber; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumberList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.http.converter.AvailablePhoneNumberConverter; -import org.mobicents.servlet.restcomm.http.converter.AvailablePhoneNumberListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.loader.ObjectFactory; -import org.mobicents.servlet.restcomm.loader.ObjectInstantiationException; -import org.mobicents.servlet.restcomm.provisioning.number.api.ContainerConfiguration; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumber; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberProvisioningManager; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thoughtworks.xstream.XStream; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.loader.ObjectInstantiationException; +import org.restcomm.connect.dao.entities.AvailablePhoneNumber; +import org.restcomm.connect.dao.entities.AvailablePhoneNumberList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.AvailablePhoneNumberConverter; +import org.restcomm.connect.http.converter.AvailablePhoneNumberListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.provisioning.number.api.PhoneNumber; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManager; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManagerProvider; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author jean.deruelle@telestax.com */ @ThreadSafe -public abstract class AvailablePhoneNumbersEndpoint extends AbstractEndpoint { +public abstract class AvailablePhoneNumbersEndpoint extends SecuredEndpoint { @Context protected ServletContext context; protected PhoneNumberProvisioningManager phoneNumberProvisioningManager; - private DaoManager daos; private XStream xstream; protected Gson gson; @@ -77,9 +66,9 @@ public AvailablePhoneNumbersEndpoint() { @PostConstruct public void init() throws ObjectInstantiationException { configuration = (Configuration) context.getAttribute(Configuration.class.getName()); - daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); super.init(configuration.subset("runtime-settings")); + /* phoneNumberProvisioningManager = (PhoneNumberProvisioningManager) context.getAttribute("PhoneNumberProvisioningManager"); if(phoneNumberProvisioningManager == null) { final String phoneNumberProvisioningManagerClass = configuration.getString("phone-number-provisioning[@class]"); @@ -92,6 +81,10 @@ public void init() throws ObjectInstantiationException { phoneNumberProvisioningManager.init(phoneNumberProvisioningConfiguration, telestaxProxyConfiguration, containerConfiguration); context.setAttribute("phoneNumberProvisioningManager", phoneNumberProvisioningManager); } + */ + // get manager from context or create it if it does not exist + phoneNumberProvisioningManager = new PhoneNumberProvisioningManagerProvider(configuration, context).get(); + xstream = new XStream(); xstream.alias("RestcommResponse", RestCommResponse.class); @@ -105,11 +98,7 @@ public void init() throws ObjectInstantiationException { } protected Response getAvailablePhoneNumbers(final String accountSid, final String isoCountryCode, PhoneNumberSearchFilters listFilters, String filterPattern, final MediaType responseType) { - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Read:AvailablePhoneNumbers"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + secure(accountsDao.getAccount(accountSid), "RestComm:Read:AvailablePhoneNumbers"); String searchPattern = ""; if (filterPattern != null && !filterPattern.isEmpty()) { for(int i = 0; i < filterPattern.length(); i ++) { @@ -132,10 +121,10 @@ protected Response getAvailablePhoneNumbers(final String accountSid, final Strin final List phoneNumbers = phoneNumberProvisioningManager.searchForNumbers(isoCountryCode, listFilters); List availablePhoneNumbers = toAvailablePhoneNumbers(phoneNumbers); - if (MediaType.APPLICATION_XML_TYPE == responseType) { + if (MediaType.APPLICATION_XML_TYPE.equals(responseType)) { return ok(xstream.toXML(new RestCommResponse(new AvailablePhoneNumberList(availablePhoneNumbers))), MediaType.APPLICATION_XML).build(); - } else if (MediaType.APPLICATION_JSON_TYPE == responseType) { + } else if (MediaType.APPLICATION_JSON_TYPE.equals(responseType)) { return ok(gson.toJson(phoneNumbers), MediaType.APPLICATION_JSON).build(); } return status(INTERNAL_SERVER_ERROR).build(); @@ -151,7 +140,7 @@ private List toAvailablePhoneNumbers(List pho final AvailablePhoneNumber number = new AvailablePhoneNumber(phoneNumber.getFriendlyName(), phoneNumber.getPhoneNumber(), phoneNumber.getLata(), phoneNumber.getRateCenter(), phoneNumber.getLatitude(), phoneNumber.getLongitude(), phoneNumber.getRegion(), - phoneNumber.getPostalCode(), phoneNumber.getIsoCountry(), phoneNumber.isVoiceCapable(), + phoneNumber.getPostalCode(), phoneNumber.getIsoCountry(), phoneNumber.getCost(), phoneNumber.isVoiceCapable(), phoneNumber.isSmsCapable(), phoneNumber.isMmsCapable(), phoneNumber.isFaxCapable()); availablePhoneNumbers.add(number); } @@ -179,9 +168,11 @@ public static String getNumber(char letter) { return "0"; } + /* @SuppressWarnings("unchecked") private List getOutboundInterfaces() { final List uris = (List) context.getAttribute(SipServlet.OUTBOUND_INTERFACES); return uris; } + */ } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersJsonEndpoint.java similarity index 91% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersJsonEndpoint.java index d73a029dc0..c7cb42ad05 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersJsonEndpoint.java @@ -17,8 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -29,9 +30,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -45,6 +47,7 @@ public AvailablePhoneNumbersJsonEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, @QueryParam("SmsEnabled") String smsEnabled, diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileJsonEndpoint.java similarity index 90% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileJsonEndpoint.java index fe24dfbbfb..ec2849cfeb 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileJsonEndpoint.java @@ -17,8 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -29,9 +30,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -45,6 +47,7 @@ public AvailablePhoneNumbersMobileJsonEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, @QueryParam("SmsEnabled") String smsEnabled, diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileXmlEndpoint.java similarity index 88% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileXmlEndpoint.java index dd2378fe67..9b2b8ffeb2 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersMobileXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersMobileXmlEndpoint.java @@ -17,22 +17,21 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; - -import static javax.ws.rs.core.MediaType.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import static javax.ws.rs.core.Response.*; import static javax.ws.rs.core.Response.Status.*; - -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -46,6 +45,7 @@ public AvailablePhoneNumbersMobileXmlEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, @QueryParam("SmsEnabled") String smsEnabled, @@ -84,7 +84,7 @@ public Response getAvailablePhoneNumber(@PathParam("accountSid") final String ac PhoneNumberSearchFilters listFilters = new PhoneNumberSearchFilters(areaCode, null, smsEnabledBool, mmsEnabledBool, voiceEnabledBool, faxEnabledBool, ussdEnabledBool, null, null, null, null, null, null, null, rangeSizeInt, rangeIndexInt, PhoneNumberType.Mobile); - return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, APPLICATION_XML_TYPE); + return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, MediaType.APPLICATION_XML_TYPE); } else { return status(BAD_REQUEST).build(); } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java index 7b4a1c4235..8f8388809d 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeJsonEndpoint.java @@ -17,8 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -29,9 +30,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -45,6 +47,7 @@ public AvailablePhoneNumbersTollFreeJsonEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java similarity index 83% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java index 35de7e8701..485ead9fe6 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersTollFreeXmlEndpoint.java @@ -17,22 +17,21 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; - -import static javax.ws.rs.core.MediaType.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import static javax.ws.rs.core.Response.*; import static javax.ws.rs.core.Response.Status.*; - -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -46,6 +45,7 @@ public AvailablePhoneNumbersTollFreeXmlEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, @@ -62,7 +62,7 @@ public Response getAvailablePhoneNumber(@PathParam("accountSid") final String ac PhoneNumberSearchFilters listFilters = new PhoneNumberSearchFilters(areaCode, null, null, Boolean.TRUE, null, null, null, null, null, null, null, null, null, null, rangeSizeInt, rangeIndexInt, PhoneNumberType.TollFree); - return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, APPLICATION_XML_TYPE); + return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, MediaType.APPLICATION_XML_TYPE); } else { return status(BAD_REQUEST).build(); } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersXmlEndpoint.java similarity index 89% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersXmlEndpoint.java index bf122dfae8..e422ed643c 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/AvailablePhoneNumbersXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AvailablePhoneNumbersXmlEndpoint.java @@ -17,22 +17,21 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; +import com.sun.jersey.spi.container.ResourceFilters; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; - -import static javax.ws.rs.core.MediaType.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import static javax.ws.rs.core.Response.*; import static javax.ws.rs.core.Response.Status.*; - -import javax.ws.rs.core.Response; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberSearchFilters; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.filters.ExtensionFilter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberSearchFilters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author gvagenas @@ -46,6 +45,7 @@ public AvailablePhoneNumbersXmlEndpoint() { } @GET + @ResourceFilters({ ExtensionFilter.class }) public Response getAvailablePhoneNumber(@PathParam("accountSid") final String accountSid, @PathParam("IsoCountryCode") final String isoCountryCode, @QueryParam("AreaCode") String areaCode, @QueryParam("Contains") String filterPattern, @QueryParam("SmsEnabled") String smsEnabled, @@ -92,7 +92,7 @@ public Response getAvailablePhoneNumber(@PathParam("accountSid") final String ac PhoneNumberSearchFilters listFilters = new PhoneNumberSearchFilters(areaCode, null, smsEnabledBool, mmsEnabledBool, voiceEnabledBool, faxEnabledBool, ussdEnabledBool, nearNumber, nearLatLong, distance, inPostalCode, inRegion, inRateCenter, inLata, rangeSizeInt, rangeIndexInt, phoneNumberType); - return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, APPLICATION_XML_TYPE); + return getAvailablePhoneNumbers(accountSid, isoCountryCode, listFilters, filterPattern, MediaType.APPLICATION_XML_TYPE); } else { return status(BAD_REQUEST).build(); } 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 new file mode 100644 index 0000000000..678b8f33a7 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsEndpoint.java @@ -0,0 +1,673 @@ +/* + * 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; + +import akka.actor.ActorRef; +import akka.pattern.AskTimeoutException; +import akka.util.Timeout; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.thoughtworks.xstream.XStream; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.amazonS3.RecordingSecurityLevel; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.telephony.CreateCallType; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordFilter; +import org.restcomm.connect.dao.entities.CallDetailRecordList; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.RecordingList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.CallDetailRecordConverter; +import org.restcomm.connect.http.converter.CallDetailRecordListConverter; +import org.restcomm.connect.http.converter.RecordingConverter; +import org.restcomm.connect.http.converter.RecordingListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.mscontrol.api.messages.Mute; +import org.restcomm.connect.mscontrol.api.messages.Unmute; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallManagerResponse; +import org.restcomm.connect.telephony.api.CallResponse; +import org.restcomm.connect.telephony.api.CreateCall; +import org.restcomm.connect.telephony.api.ExecuteCallScript; +import org.restcomm.connect.telephony.api.GetCall; +import org.restcomm.connect.telephony.api.GetCallInfo; +import org.restcomm.connect.telephony.api.Hangup; +import org.restcomm.connect.telephony.api.UpdateCallScript; + +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.servlet.sip.SipServletResponse; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import java.net.URI; +import java.net.URL; +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; + +import static akka.pattern.Patterns.ask; +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.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.GONE; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +//import org.joda.time.DateTime; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author gvagenas@gmail.com (George Vagenas) + */ +@NotThreadSafe +public abstract class CallsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected ActorRef callManager; + protected DaoManager daos; + protected Gson gson; + protected GsonBuilder builder; + protected XStream xstream; + protected CallDetailRecordListConverter listConverter; + protected AccountsDao accountsDao; + protected RecordingsDao recordingsDao; + protected String instanceId; + protected RecordingSecurityLevel securityLevel = RecordingSecurityLevel.SECURE; + protected boolean normalizePhoneNumbers; + + public CallsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + Configuration amazonS3Configuration = configuration.subset("amazon-s3"); + configuration = configuration.subset("runtime-settings"); + callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager"); + daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); + accountsDao = daos.getAccountsDao(); + recordingsDao = daos.getRecordingsDao(); + super.init(configuration); + CallDetailRecordConverter converter = new CallDetailRecordConverter(configuration); + listConverter = new CallDetailRecordListConverter(configuration); + final RecordingConverter recordingConverter = new RecordingConverter(configuration); + builder = new GsonBuilder(); + builder.registerTypeAdapter(CallDetailRecord.class, converter); + builder.registerTypeAdapter(CallDetailRecordList.class, listConverter); + builder.registerTypeAdapter(Recording.class, recordingConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(recordingConverter); + xstream.registerConverter(new RecordingListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + + normalizePhoneNumbers = configuration.getBoolean("normalize-numbers-for-outbound-calls"); + if(!amazonS3Configuration.isEmpty()) { // Do not fail with NPE is amazonS3Configuration is not present for older install + boolean amazonS3Enabled = amazonS3Configuration.getBoolean("enabled"); + if (amazonS3Enabled) { + securityLevel = RecordingSecurityLevel.valueOf(amazonS3Configuration.getString("security-level", "secure").toUpperCase()); + recordingConverter.setSecurityLevel(securityLevel); + } + } + } + + protected Response getCall(final String accountSid, final String sid, final MediaType responseType) { + Account account = daos.getAccountsDao().getAccount(accountSid); + secure(account, "RestComm:Read:Calls"); + final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + final CallDetailRecord cdr = dao.getCallDetailRecord(new Sid(sid)); + if (cdr == null) { + return status(NOT_FOUND).build(); + } else { + secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(cdr); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(cdr), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + // Issue 153: https://bitbucket.org/telestax/telscale-restcomm/issue/153 + // Issue 110: https://bitbucket.org/telestax/telscale-restcomm/issue/110 + protected Response getCalls(final String accountSid, UriInfo info, MediaType responseType) { + Account account = daos.getAccountsDao().getAccount(accountSid); + secure(account, "RestComm:Read:Calls"); + + boolean localInstanceOnly = true; + try { + String localOnly = info.getQueryParameters().getFirst("localOnly"); + if (localOnly != null && localOnly.equalsIgnoreCase("false")) + localInstanceOnly = false; + } catch (Exception e) { + } + // shall we include sub-accounts cdrs in our query ? + boolean querySubAccounts = false; // be default we don't + String querySubAccountsParam = info.getQueryParameters().getFirst("SubAccounts"); + if (querySubAccountsParam != null && querySubAccountsParam.equalsIgnoreCase("true")) + querySubAccounts = true; + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + // String afterSid = info.getQueryParameters().getFirst("AfterSid"); + String recipient = info.getQueryParameters().getFirst("To"); + String sender = info.getQueryParameters().getFirst("From"); + String status = info.getQueryParameters().getFirst("Status"); + String startTime = info.getQueryParameters().getFirst("StartTime"); + String endTime = info.getQueryParameters().getFirst("EndTime"); + String parentCallSid = info.getQueryParameters().getFirst("ParentCallSid"); + String conferenceSid = info.getQueryParameters().getFirst("ConferenceSid"); + String reverse = info.getQueryParameters().getFirst("Reverse"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page == "0") ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + // Shall we query cdrs of sub-accounts too ? + // if we do, we need to find the sub-accounts involved first + List ownerAccounts = null; + if (querySubAccounts) { + ownerAccounts = new ArrayList(); + ownerAccounts.add(accountSid); // we will also return parent account cdrs + ownerAccounts.addAll(accountsDao.getSubAccountSidsRecursive(new Sid(accountSid))); + } + + CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + + CallDetailRecordFilter filterForTotal; + try { + + if (localInstanceOnly) { + filterForTotal = new CallDetailRecordFilter(accountSid, ownerAccounts, recipient, sender, status, startTime, endTime, + parentCallSid, conferenceSid, null, null); + } else { + filterForTotal = new CallDetailRecordFilter(accountSid, ownerAccounts, recipient, sender, status, startTime, endTime, + parentCallSid, conferenceSid, null, null, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalCallDetailRecords(filterForTotal); + + if (reverse != null) { + if (reverse.equalsIgnoreCase("true")){ + if (total > Integer.parseInt(pageSize)){ + if (total > Integer.parseInt(pageSize)*(Integer.parseInt(page) + 1)){ + offset = total - Integer.parseInt(pageSize)*(Integer.parseInt(page) + 1); + limit = Integer.parseInt(pageSize); + } + else{ + offset = 0; + limit = total - Integer.parseInt(pageSize)*Integer.parseInt(page); + } + } + } + } + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + CallDetailRecordFilter filter; + try { + if (localInstanceOnly) { + filter = new CallDetailRecordFilter(accountSid, ownerAccounts, recipient, sender, status, startTime, endTime, + parentCallSid, conferenceSid, limit, offset); + } else { + filter = new CallDetailRecordFilter(accountSid, ownerAccounts, recipient, sender, status, startTime, endTime, + parentCallSid, conferenceSid, limit, offset, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getCallDetailRecords(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri("/"+getApiVersion(null)+"/"+info.getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new CallDetailRecordList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new CallDetailRecordList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } + + private void normalize(final MultivaluedMap data) throws IllegalArgumentException { + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + final String from = data.getFirst("From"); + if (!from.contains("@")) { + // https://github.com/Mobicents/RestComm/issues/150 Don't complain in case of URIs in the From header + data.remove("From"); + try { + data.putSingle("From", phoneNumberUtil.format(phoneNumberUtil.parse(from, "US"), PhoneNumberFormat.E164)); + } catch (final NumberParseException exception) { + throw new IllegalArgumentException(exception); + } + } + final String to = data.getFirst("To"); + // Only try to normalize phone numbers. + if (to.startsWith("client")) { + if (to.split(":").length != 2) { + throw new IllegalArgumentException(to + " is an invalid client identifier."); + } + } else if (!to.contains("@")) { + data.remove("To"); + try { + data.putSingle("To", phoneNumberUtil.format(phoneNumberUtil.parse(to, "US"), PhoneNumberFormat.E164)); + } catch (final NumberParseException exception) { + throw new IllegalArgumentException(exception); + } + } + URI.create(data.getFirst("Url")); + } + + @SuppressWarnings("unchecked") + protected Response putCall(final String accountSid, final MultivaluedMap data, final MediaType responseType) { + final Sid accountId; + try { + accountId = new Sid(accountSid); + } catch (final IllegalArgumentException exception){ + return status(INTERNAL_SERVER_ERROR).entity(buildErrorResponseBody(exception.getMessage(),responseType)).build(); + } + secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Create:Calls"); + try { + validate(data); + if (normalizePhoneNumbers) + normalize(data); + } catch (final RuntimeException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + + URI statusCallback = null; + String statusCallbackMethod = "POST"; + List statusCallbackEvent = new LinkedList(); + statusCallbackEvent.add("initiated"); + statusCallbackEvent.add("ringing"); + statusCallbackEvent.add("answered"); + statusCallbackEvent.add("completed"); + + final String from = data.getFirst("From").trim(); + final String to = data.getFirst("To").trim(); + final String username = data.getFirst("Username"); + final String password = data.getFirst("Password"); + Integer timeout = getTimeout(data); + timeout = timeout != null ? timeout : 30; + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + final URI rcmlUrl = getUrl("Url", data); + + try { + if (data.containsKey("StatusCallback")) { + statusCallback = new URI(data.getFirst("StatusCallback").trim()); + } + } catch (Exception e) { + //Handle Exception + } + + if (statusCallback != null) { + if (data.containsKey("StatusCallbackMethod")) { + statusCallbackMethod = data.getFirst("StatusCallbackMethod").trim(); + } + if (data.containsKey("StatusCallbackEvent")) { + statusCallbackEvent.addAll(Arrays.asList(data.getFirst("StatusCallbackEvent").trim().split(","))); + } + } + + CreateCall create = null; + try { + if (to.contains("@")) { + create = new CreateCall(from, to, username, password, true, timeout, CreateCallType.SIP, + accountId, null, statusCallback, statusCallbackMethod, statusCallbackEvent); + } else if (to.startsWith("client")) { + create = new CreateCall(from, to, username, password, true, timeout, CreateCallType.CLIENT, + accountId, null, statusCallback, statusCallbackMethod, statusCallbackEvent); + } else { + create = new CreateCall(from, to, username, password, true, timeout, CreateCallType.PSTN, + accountId, null, statusCallback, statusCallbackMethod, statusCallbackEvent); + } + create.setCreateCDR(false); + if (callManager == null) + callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager"); + Future future = (Future) ask(callManager, create, expires); + Object object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + Class klass = object.getClass(); + if (CallManagerResponse.class.equals(klass)) { + final CallManagerResponse managerResponse = (CallManagerResponse) object; + if (managerResponse.succeeded()) { + List dialBranches; + if (managerResponse.get() instanceof List) { + dialBranches = (List) managerResponse.get(); + } else { + dialBranches = new CopyOnWriteArrayList(); + dialBranches.add(managerResponse.get()); + } + List cdrs = new CopyOnWriteArrayList(); + for (ActorRef call : dialBranches) { + future = (Future) ask(call, new GetCallInfo(), expires); + object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + klass = object.getClass(); + if (CallResponse.class.equals(klass)) { + final CallResponse callResponse = (CallResponse) object; + if (callResponse.succeeded()) { + final CallInfo callInfo = callResponse.get(); + // Execute the call script. + final String version = getApiVersion(data); + final URI url = rcmlUrl; + final String method = getMethod("Method", data); + final URI fallbackUrl = getUrl("FallbackUrl", data); + final String fallbackMethod = getMethod("FallbackMethod", data); + final ExecuteCallScript execute = new ExecuteCallScript(call, accountId, version, url, method, + fallbackUrl, fallbackMethod, timeout); + callManager.tell(execute, null); + cdrs.add(daos.getCallDetailRecordsDao().getCallDetailRecord(callInfo.sid())); + } + } + } + if (APPLICATION_XML_TYPE == responseType) { + if (cdrs.size()==1) { + return ok(xstream.toXML(cdrs.get(0)), APPLICATION_XML).build(); + } else { + final RestCommResponse response = new RestCommResponse(new CallDetailRecordList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } + } else if (APPLICATION_JSON_TYPE == responseType) { + if (cdrs.size()==1) { + return ok(gson.toJson(cdrs.get(0)), APPLICATION_JSON).build(); + } else { + return ok(gson.toJson(cdrs), APPLICATION_JSON).build(); + } + } else { + return null; + } +// if (APPLICATION_JSON_TYPE == responseType) { +// return ok(gson.toJson(cdrs), APPLICATION_JSON).build(); +// } else if (APPLICATION_XML_TYPE == responseType) { +// return ok(xstream.toXML(new RestCommResponse(cdrs)), APPLICATION_XML).build(); +// } else { +// return null; +// } + } else { + return status(INTERNAL_SERVER_ERROR).entity(managerResponse.cause().getMessage()).build(); + } + } + return status(INTERNAL_SERVER_ERROR).build(); + } catch (final Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } + + // Issue 139: https://bitbucket.org/telestax/telscale-restcomm/issue/139 + @SuppressWarnings("unchecked") + protected Response updateCall(final String sid, final String callSid, final MultivaluedMap data, final MediaType responseType) { + final Sid accountSid = new Sid(sid); + Account account = daos.getAccountsDao().getAccount(accountSid); + secure(account, "RestComm:Modify:Calls"); + + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + + final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + CallDetailRecord cdr = null; + try { + cdr = dao.getCallDetailRecord(new Sid(callSid)); + + if (cdr != null) { + //allow super admin to perform LCM on any call - https://telestax.atlassian.net/browse/RESTCOMM-1171 + if(!isSuperAdmin()){ + secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD); + } + } else { + return Response.status(NOT_ACCEPTABLE).build(); + } + } catch (Exception e) { + return status(BAD_REQUEST).build(); + } + + final String url = data.getFirst("Url"); + String method = data.getFirst("Method"); + final String status = data.getFirst("Status"); + final String fallBackUrl = data.getFirst("FallbackUrl"); + String fallBackMethod = data.getFirst("FallbackMethod"); + final String statusCallBack = data.getFirst("StatusCallback"); + String statusCallbackMethod = data.getFirst("StatusCallbackMethod"); + //Restcomm- Move connected call leg (if exists) to the new URL + Boolean moveConnectedCallLeg = Boolean.valueOf(data.getFirst("MoveConnectedCallLeg")); + Boolean mute = Boolean.valueOf(data.getFirst("Mute")); + + String callPath = null; + final ActorRef call; + final CallInfo callInfo; + + try { + callPath = cdr.getCallPath(); + Future future = (Future) ask(callManager, new GetCall(callPath), expires); + call = (ActorRef) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + + future = (Future) ask(call, new GetCallInfo(), expires); + CallResponse response = (CallResponse) Await.result(future, + Duration.create(10, TimeUnit.SECONDS)); + callInfo = response.get(); + } catch (AskTimeoutException ate) { + final String msg ="Call is already completed."; + if(logger.isDebugEnabled()) + logger.debug("Modify Call LCM for call sid:"+callSid+ " AskTimeout while getting call: "+ callPath +" restcomm will send "+GONE +" with msg: "+msg); + return status(GONE).entity(msg).build(); + } catch (Exception exception) { + logger.error("Exception while trying to update call callPath: "+callPath+" callSid: "+callSid, exception); + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + + if (method == null) + method = "POST"; + + if (url == null && status == null && mute == null ) { + // Throw exception. We can either redirect a running call using Url or change the state of a Call with Status + final String errorMessage = "You can either redirect a running call using \"Url\" or change the state of a Call with \"Status\" or mute a call using \"Mute=true\""; + return status(javax.ws.rs.core.Response.Status.CONFLICT).entity(errorMessage).build(); + } + + // Modify state of a call + if (status != null) { + if (status.equalsIgnoreCase("canceled")) { + if (callInfo.state().name().equalsIgnoreCase("queued") || callInfo.state().name().equalsIgnoreCase("ringing")) { + if (call != null) { + call.tell(new Hangup(), null); + } + } else if (callInfo.state().name().equalsIgnoreCase("wait_for_answer")){ + // We can cancel Wait For Answer calls + if (call != null) { + call.tell(new Hangup(SipServletResponse.SC_REQUEST_TERMINATED), null); + } + } + else{ + // Do Nothing. We can only cancel Queued or Ringing calls + } + } + + if (status.equalsIgnoreCase("completed")) { + // Specifying "completed" will attempt to hang up a call even if it's already in progress. + if (call != null) { + call.tell(new Hangup(SipServletResponse.SC_REQUEST_TERMINATED), null); + } + } + } + + if(mute != null && call != null){ + try{ + muteUnmuteCall(mute, callInfo, call, cdr, dao); + } catch (Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } + + if (url != null && call != null) { + try { + final String version = getApiVersion(data); + final URI uri = (new URL(url)).toURI(); + + URI fallbackUri = (fallBackUrl != null) ? (new URL(fallBackUrl)).toURI() : null; + fallBackMethod = (fallBackMethod == null) ? "POST" : fallBackMethod; + URI callbackUri = (statusCallBack != null) ? (new URL(statusCallBack)).toURI() : null; + statusCallbackMethod = (statusCallbackMethod == null) ? "POST" : statusCallbackMethod; + + final UpdateCallScript update = new UpdateCallScript(call, accountSid, version, uri, method, fallbackUri, + fallBackMethod, callbackUri, statusCallbackMethod, moveConnectedCallLeg); + callManager.tell(update, null); + } catch (Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } else { + if (logger.isInfoEnabled()) { + if (url == null) { + logger.info("Problem during Call Update, Url is null. Make sure you provide Url parameter"); + } + if (call == null) { + logger.info("Problem during Call update, Call is null. Make sure you provide the proper Call SID"); + } + } + } + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(cdr), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + return ok(xstream.toXML(new RestCommResponse(cdr)), APPLICATION_XML).build(); + } else { + return null; + } + } + + private Integer getTimeout(final MultivaluedMap data) { + Integer result = 60; + if (data.containsKey("Timeout")) { + result = Integer.parseInt(data.getFirst("Timeout")); + } + return result; + } + + private void validate(final MultivaluedMap data) throws NullPointerException { + if (!data.containsKey("From")) { + throw new NullPointerException("From can not be null."); + } else if (!data.containsKey("To")) { + throw new NullPointerException("To can not be null."); + } else if (!data.containsKey("Url")) { + throw new NullPointerException("Url can not be null."); + } + } + + protected Response getRecordingsByCall(final String accountSid, final String callSid, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Recordings"); + + final List recordings = recordingsDao.getRecordingsByCall(new Sid(callSid)); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(recordings), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new RecordingList(recordings)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + + } + + /** + * @param mute - true if we want to mute the call, false otherwise. + * @param callInfo - CallInfo + * @param call - ActorRef for the call + * @param cdr - CallDetailRecord of given call to update mute status in db + * @param dao - CallDetailRecordsDao for calls to update mute status in db + */ + protected void muteUnmuteCall(Boolean mute, CallInfo callInfo, ActorRef call, CallDetailRecord cdr, CallDetailRecordsDao dao){ + if(callInfo.state().name().equalsIgnoreCase("IN_PROGRESS") || callInfo.state().name().equalsIgnoreCase("in-progress")){ + if(mute){ + if(!callInfo.isMuted()){ + call.tell(new Mute(), null); + }else{ + if(logger.isInfoEnabled()) + logger.info("Call is already muted."); + } + }else{ + if(callInfo.isMuted()){ + call.tell(new Unmute(), null); + }else{ + if(logger.isInfoEnabled()) + logger.info("Call is not muted."); + } + } + cdr = cdr.setMuted(mute); + dao.updateCallDetailRecord(cdr); + }else{ + // Do Nothing. We can only mute/unMute in progress calls + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsJsonEndpoint.java similarity index 94% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsJsonEndpoint.java index e06a9da96f..07b111d0b9 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsJsonEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.*; @@ -30,7 +30,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsXmlEndpoint.java similarity index 77% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsXmlEndpoint.java index 2e5c4315d5..4d13f20557 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/CallsXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsXmlEndpoint.java @@ -17,12 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import static javax.ws.rs.core.MediaType.*; @@ -30,8 +31,9 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import javax.ws.rs.core.MediaType; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -75,4 +77,18 @@ public Response modifyCall(@PathParam("accountSid") final String accountSid, @Pa return updateCall(accountSid, sid, data, APPLICATION_XML_TYPE); } + @GET + @Path("/{callSid}/Recordings.json") + @Produces(MediaType.APPLICATION_JSON) + public Response getRecordingsByCallJson(@PathParam("accountSid") String accountSid, @PathParam("callSid") String callSid) { + return getRecordingsByCall(accountSid, callSid, MediaType.APPLICATION_JSON_TYPE); + } + + @GET + @Path("/{callSid}/Recordings") + @Produces(MediaType.APPLICATION_XML) + public Response getRecordingsByCallXml(@PathParam("accountSid") String accountSid, @PathParam("callSid") String callSid) { + return getRecordingsByCall(accountSid, callSid, MediaType.APPLICATION_XML_TYPE); + } + } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsEndpoint.java new file mode 100644 index 0000000000..dab2aa8c06 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsEndpoint.java @@ -0,0 +1,308 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.dao.entities.ClientList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.ClientConverter; +import org.restcomm.connect.http.converter.ClientListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.exceptions.PasswordTooWeak; +import org.restcomm.connect.identity.passwords.PasswordValidator; +import org.restcomm.connect.identity.passwords.PasswordValidatorFactory; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.net.URI; +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.Response.ok; +import static javax.ws.rs.core.Response.status; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@NotThreadSafe +public abstract class ClientsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected ClientsDao dao; + protected Gson gson; + protected XStream xstream; + protected AccountsDao accountsDao; + + public ClientsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + dao = storage.getClientsDao(); + accountsDao = storage.getAccountsDao(); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + final ClientConverter converter = new ClientConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Client.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new ClientListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + private Client createFrom(final Sid accountSid, final MultivaluedMap data) throws PasswordTooWeak { + final Client.Builder builder = Client.builder(); + final Sid sid = Sid.generate(Sid.Type.CLIENT); + builder.setSid(sid); + builder.setApiVersion(getApiVersion(data)); + builder.setFriendlyName(getFriendlyName(data.getFirst("Login"), data)); + builder.setAccountSid(accountSid); + builder.setLogin(data.getFirst("Login")); + // Validate the password. Should be strong enough + String password = data.getFirst("Password"); + PasswordValidator validator = PasswordValidatorFactory.createDefault(); + if (!validator.isStrongEnough(password)) + throw new PasswordTooWeak(); + builder.setPassword(password); + builder.setStatus(getStatus(data)); + URI voiceUrl = getUrl("VoiceUrl", data); + if (voiceUrl != null && voiceUrl.toString().equals("")) { + voiceUrl=null; + } + builder.setVoiceUrl(voiceUrl); + String method = getMethod("VoiceMethod", data); + if (method == null || method.isEmpty() || method.equals("")) { + method = "POST"; + } + builder.setVoiceMethod(method); + builder.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); + builder.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); + // skip null/empty VoiceApplicationSid's (i.e. leave null) + if (data.containsKey("VoiceApplicationSid")) { + if ( ! org.apache.commons.lang.StringUtils.isEmpty( data.getFirst("VoiceApplicationSid") ) ) + builder.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); + } + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Clients/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + if (data.containsKey("IsPushEnabled") && getBoolean("IsPushEnabled", data)) { + builder.setPushClientIdentity(sid.toString()); + } + return builder.build(); + } + + protected Response getClient(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:Clients"); + final Client client = dao.getClient(new Sid(sid)); + if (client == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, client.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(client); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(client), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getClients(final String accountSid, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Clients"); + final List clients = dao.getClients(new Sid(accountSid)); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new ClientList(clients)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(clients), APPLICATION_JSON).build(); + } else { + return null; + } + } + + private String getFriendlyName(final String login, final MultivaluedMap data) { + String friendlyName = login; + if (data.containsKey("FriendlyName")) { + friendlyName = data.getFirst("FriendlyName"); + } + return friendlyName; + } + + private int getStatus(final MultivaluedMap data) { + int status = Client.ENABLED; + if (data.containsKey("Status")) { + try { + status = Integer.parseInt(data.getFirst("Status")); + } catch (final NumberFormatException ignored) { + } + } + return status; + } + + public Response putClient(final String accountSid, final MultivaluedMap data, final MediaType responseType) { + final Account account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Create:Clients"); + try { + validate(data); + } catch (final NullPointerException | IllegalArgumentException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + + // Issue 109: https://bitbucket.org/telestax/telscale-restcomm/issue/109 + Client client = dao.getClient(data.getFirst("Login"), account.getOrganizationSid()); + if (client == null) { + try { + client = createFrom(new Sid(accountSid), data); + } catch (PasswordTooWeak passwordTooWeak) { + return status(BAD_REQUEST).entity(buildErrorResponseBody("Password too weak",responseType)).type(responseType).build(); + } + dao.addClient(client); + } else if (!client.getAccountSid().toString().equals(accountSid)) { + return status(CONFLICT) + .entity("A client with the same name was already created by another account. Please, choose a different name and try again.") + .build(); + } + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(client); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(client), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response updateClient(final String accountSid, final String sid, final MultivaluedMap data, + final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Modify:Clients"); + Client client = dao.getClient(new Sid(sid)); + if (client == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, client.getAccountSid(), SecuredType.SECURED_STANDARD ); + try { + client = update(client, data); + dao.updateClient(client); + } catch (PasswordTooWeak passwordTooWeak) { + return status(BAD_REQUEST).entity(buildErrorResponseBody("Password too weak",responseType)).type(responseType).build(); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(client); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(client), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private void validate(final MultivaluedMap data) throws RuntimeException { + if (!data.containsKey("Login")) { + throw new NullPointerException("Login can not be null."); + } else if (!data.containsKey("Password")) { + throw new NullPointerException("Password can not be null."); + } + // https://github.com/RestComm/Restcomm-Connect/issues/1979 + if (data.getFirst("Login").contains("@")) { + throw new IllegalArgumentException("Login contains invalid character: @ "+data.getFirst("Login")); + } + } + + private Client update(Client client, final MultivaluedMap data) throws PasswordTooWeak { + if (data.containsKey("FriendlyName")) { + client = client.setFriendlyName(data.getFirst("FriendlyName")); + } + if (data.containsKey("Password")) { + String password = data.getFirst("Password"); + PasswordValidator validator = PasswordValidatorFactory.createDefault(); + if (!validator.isStrongEnough(password)) { + throw new PasswordTooWeak(); + } + client = client.setPassword(password); + } + if (data.containsKey("Status")) { + client = client.setStatus(getStatus(data)); + } + if (data.containsKey("VoiceUrl")) { + URI uri = getUrl("VoiceUrl", data); + client = client.setVoiceUrl(isEmpty(uri.toString()) ? null : uri); + } + if (data.containsKey("VoiceMethod")) { + client = client.setVoiceMethod(getMethod("VoiceMethod", data)); + } + if (data.containsKey("VoiceFallbackUrl")) { + URI uri = getUrl("VoiceFallbackUrl", data); + client = client.setVoiceFallbackUrl(isEmpty(uri.toString()) ? null :uri); + } + if (data.containsKey("VoiceFallbackMethod")) { + client = client.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); + } + if (data.containsKey("VoiceApplicationSid")) { + if (org.apache.commons.lang.StringUtils.isEmpty(data.getFirst("VoiceApplicationSid"))) { + client = client.setVoiceApplicationSid(null); + } else { + client = client.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); + } + } + if (data.containsKey("IsPushEnabled")) { + if (getBoolean("IsPushEnabled", data)) { + client = client.setPushClientIdentity(client.getSid().toString()); + } else { + client = client.setPushClientIdentity(null); + } + } + return client; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsJsonEndpoint.java similarity index 93% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsJsonEndpoint.java index 2b2497deed..0e6a1e0e79 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsJsonEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; @@ -28,7 +28,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsXmlEndpoint.java similarity index 80% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsXmlEndpoint.java index 894cb99001..9ad330f1d5 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/ClientsXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ClientsXmlEndpoint.java @@ -17,11 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; -import static javax.ws.rs.core.MediaType.*; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -32,10 +33,10 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.apache.shiro.authz.AuthorizationException; - -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -48,13 +49,16 @@ public ClientsXmlEndpoint() { } private Response deleteClient(final String accountSid, final String sid) { - try { - secure(super.accountsDao.getAccount(accountSid), "RestComm:Delete:Clients"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); + Account operatedAccount =super.accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Delete:Clients"); + Client client = dao.getClient(new Sid(sid)); + if (client != null) { + secure(operatedAccount, client.getAccountSid(), SecuredType.SECURED_STANDARD); + dao.removeClient(new Sid(sid)); + return ok().build(); + } else { + return status(Response.Status.NOT_FOUND).build(); } - dao.removeClient(new Sid(sid)); - return ok().build(); } @Path("/{sid}.json") diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesEndpoint.java new file mode 100644 index 0000000000..4ac7befbd9 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesEndpoint.java @@ -0,0 +1,197 @@ +/* + * 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; + +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.ok; +import static javax.ws.rs.core.Response.status; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; + +import java.text.ParseException; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.apache.shiro.authz.AuthorizationException; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.http.converter.ConferenceDetailRecordConverter; +import org.restcomm.connect.http.converter.ConferenceDetailRecordListConverter; +import org.restcomm.connect.dao.ConferenceDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.dao.entities.ConferenceDetailRecordFilter; +import org.restcomm.connect.dao.entities.ConferenceDetailRecordList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@NotThreadSafe +public abstract class ConferencesEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + private DaoManager daoManager; + private Gson gson; + private GsonBuilder builder; + private XStream xstream; + private ConferenceDetailRecordListConverter listConverter; + + public ConferencesEndpoint() { + super(); + } + + @PostConstruct + public void init() { + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + daoManager = (DaoManager) context.getAttribute(DaoManager.class.getName()); + super.init(configuration); + ConferenceDetailRecordConverter converter = new ConferenceDetailRecordConverter(configuration); + listConverter = new ConferenceDetailRecordListConverter(configuration); + builder = new GsonBuilder(); + builder.registerTypeAdapter(ConferenceDetailRecord.class, converter); + builder.registerTypeAdapter(ConferenceDetailRecordList.class, listConverter); + builder.setPrettyPrinting(); + builder.disableHtmlEscaping(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(listConverter); + } + + protected Response getConference(final String accountSid, final String sid, final MediaType responseType) { + Account account = daoManager.getAccountsDao().getAccount(accountSid); + try { + secure(account, "RestComm:Read:Conferences"); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + final ConferenceDetailRecordsDao dao = daoManager.getConferenceDetailRecordsDao(); + final ConferenceDetailRecord cdr = dao.getConferenceDetailRecord(new Sid(sid)); + if (cdr == null) { + return status(NOT_FOUND).build(); + } else { + try { + //secureLevelControl(daoManager.getAccountsDao(), accountSid, String.valueOf(cdr.getAccountSid())); + secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(cdr); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(cdr), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getConferences(final String accountSid, UriInfo info, MediaType responseType) { + Account account = daoManager.getAccountsDao().getAccount(accountSid); + try { + secure(account, "RestComm:Read:Conferences"); + //secureLevelControl(daoManager.getAccountsDao(), accountSid, null); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + String status = info.getQueryParameters().getFirst("Status"); + String dateCreated = info.getQueryParameters().getFirst("DateCreated"); + String dateUpdated = info.getQueryParameters().getFirst("DateUpdated"); + String friendlyName = info.getQueryParameters().getFirst("FriendlyName"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page == "0") ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + ConferenceDetailRecordsDao dao = daoManager.getConferenceDetailRecordsDao(); + + ConferenceDetailRecordFilter filterForTotal; + try { + filterForTotal = new ConferenceDetailRecordFilter(accountSid, status, dateCreated, dateUpdated, friendlyName, + null, null); + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalConferenceDetailRecords(filterForTotal); + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + ConferenceDetailRecordFilter filter; + try { + filter = new ConferenceDetailRecordFilter(accountSid, status, dateCreated, dateUpdated, friendlyName, + limit, offset); + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getConferenceDetailRecords(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri("/"+getApiVersion(null)+"/"+info.getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new ConferenceDetailRecordList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new ConferenceDetailRecordList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } + +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesJsonEndpoint.java new file mode 100644 index 0000000000..cdaff9d96c --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesJsonEndpoint.java @@ -0,0 +1,48 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@Path("/Accounts/{accountSid}/Conferences.json") +@ThreadSafe +public final class ConferencesJsonEndpoint extends ConferencesEndpoint { + public ConferencesJsonEndpoint() { + super(); + } + + @GET + public Response getConferences(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getConferences(accountSid, info, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesXmlEndpoint.java new file mode 100644 index 0000000000..374f2ce8dc --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ConferencesXmlEndpoint.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; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author maria-farooq@live.com (Maria Farooq) + */ +@Path("/Accounts/{accountSid}/Conferences") +@ThreadSafe +public final class ConferencesXmlEndpoint extends ConferencesEndpoint { + public ConferencesXmlEndpoint() { + super(); + } + + @Path("/{sid}.json") + @GET + public Response getConferenceAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getConference(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @GET + public Response getConferenceAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getConference(accountSid, sid, APPLICATION_XML_TYPE); + } + + @GET + public Response getConferences(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getConferences(accountSid, info, APPLICATION_XML_TYPE); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesEndpoint.java new file mode 100644 index 0000000000..ae75401915 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesEndpoint.java @@ -0,0 +1,265 @@ +package org.restcomm.connect.http; + +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 com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +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.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.email.EmailService; +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.http.converter.EmailMessageConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.exceptions.InvalidEmailException; +import org.restcomm.connect.identity.EmailValidator; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.MediaType.*; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + + +/** + * @author lefty .liblefty@telestax.com (Lefteris Banos) + */ +public class EmailMessagesEndpoint extends SecuredEndpoint { + private static Logger logger = Logger.getLogger(EmailMessagesEndpoint.class); + @Context + protected ServletContext context; + protected ActorSystem system; + protected Configuration configuration; + protected Configuration confemail; + protected Gson gson; + protected AccountsDao accountsDao; + ActorRef mailerService = null; + protected XStream xstream; + + // Send the email. + protected Mail emailMsg; + + public EmailMessagesEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + confemail=configuration.subset("smtp-service"); + configuration = configuration.subset("runtime-settings"); + accountsDao = storage.getAccountsDao(); + system = (ActorSystem) context.getAttribute(ActorSystem.class.getName()); + super.init(configuration); + final EmailMessageConverter converter = new EmailMessageConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Mail.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + private void normalize(final MultivaluedMap data) throws IllegalArgumentException { + final String from = data.getFirst("From"); + data.remove("From"); + try { + data.putSingle("From", validateEmail(from)); + } catch (final InvalidEmailException exception) { + throw new IllegalArgumentException(exception); + } + final String to = data.getFirst("To"); + data.remove("To"); + try { + data.putSingle("To", validateEmail(to)); + } catch (final InvalidEmailException exception) { + throw new IllegalArgumentException(exception); + } + + final String subject = data.getFirst("Subject"); + if (subject.length() > 160) { + data.remove("Subject"); + data.putSingle("Subject", subject.substring(0, 160)); + } + + if (data.containsKey("CC")) { + final String cc = data.getFirst("CC"); + data.remove("CC"); + try { + data.putSingle("CC", validateEmails(cc)); + } catch (final InvalidEmailException exception) { + throw new IllegalArgumentException(exception); + } + } + + if (data.containsKey("BCC")) { + final String bcc = data.getFirst("BCC"); + data.remove("BCC"); + try { + data.putSingle("BCC", validateEmails(bcc)); + } catch (final InvalidEmailException exception) { + throw new IllegalArgumentException(exception); + } + } + + } + + @SuppressWarnings("unchecked") + protected Response putEmailMessage(final String accountSid, final MultivaluedMap data, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Create:EmailMessages"); //need to fix for Emails. + try { + validate(data); + normalize(data); + } catch (final RuntimeException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + final String sender = data.getFirst("From"); + final String recipient = data.getFirst("To"); + final String body = data.getFirst("Body"); + final String subject = data.getFirst("Subject"); + final String cc = data.containsKey("CC")?data.getFirst("CC"):" "; + final String bcc = data.containsKey("BCC")?data.getFirst("BCC"):" "; + + try { + + // Send the email. + emailMsg = new Mail(sender, recipient, subject, body ,cc,bcc, DateTime.now(),accountSid); + if (mailerService == null){ + mailerService = session(confemail); + } + + final ActorRef observer = observer(); + mailerService.tell(new Observe(observer), observer); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(emailMsg), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(emailMsg); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + + } catch (final Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } + + + private void validate(final MultivaluedMap data) throws NullPointerException { + if (!data.containsKey("From")) { + throw new NullPointerException("From can not be null."); + } else if (!data.containsKey("To")) { + throw new NullPointerException("To can not be null."); + } else if (!data.containsKey("Body")) { + throw new NullPointerException("Body can not be null."); + } else if (!data.containsKey("Subject")) { + throw new NullPointerException("Body can not be null."); + } + } + + + public String validateEmail(String email) throws InvalidEmailException { + if (!EmailValidator.isValidEmailFormat(email)) { + String err = "Not a Valid Email Address"; + throw new InvalidEmailException(err); + } + return email; + } + + public String validateEmails(String emails) throws InvalidEmailException { + if (emails.indexOf(',') > 0) { + String[] emailsArray = emails.split(","); + for (int i = 0; i < emailsArray.length; i++) { + if (!EmailValidator.isValidEmailFormat(emailsArray[i])) { + String err = "Not a Valid Email Address:" + emailsArray[i]; + throw new InvalidEmailException(err); + } + } + } else { + if (!EmailValidator.isValidEmailFormat(emails)) { + String err = "Not a Valid Email Address"; + throw new InvalidEmailException(err); + } + } + return emails; + } + + + private ActorRef session(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + @Override + public Actor create() throws Exception { + return new EmailService(configuration); + } + }); + return system.actorOf(props); + } + + private ActorRef observer() { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new EmailSessionObserver(); + } + }); + return system.actorOf(props); + } + + private final class EmailSessionObserver extends RestcommUntypedActor { + public EmailSessionObserver() { + super(); + } + + @Override + public void onReceive(final Object message) throws Exception { + final Class klass = message.getClass(); + if (EmailResponse.class.equals(klass)) { + final EmailResponse response = (EmailResponse) message; + if (!response.succeeded()) { + logger.error( + "There was an error while sending an email :" + response.error(), + response.cause()); + } + + final UntypedActorContext context = getContext(); + final ActorRef self = self(); + mailerService.tell(new StopObserving(self), null); + context.stop(self); + }else if (Observing.class.equals(klass)){ + mailerService.tell(new EmailRequest(emailMsg), self()); + } + } + } + +} + + + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesJsonEndpoint.java new file mode 100644 index 0000000000..d00408c013 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesJsonEndpoint.java @@ -0,0 +1,46 @@ +/* + * 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; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Email/Messages.json") +@ThreadSafe +public final class EmailMessagesJsonEndpoint extends EmailMessagesEndpoint { + public EmailMessagesJsonEndpoint() { + super(); + } + + @POST + public Response putEmailMessage(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return putEmailMessage(accountSid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesXmlEndpoint.java new file mode 100644 index 0000000000..954f56cf22 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/EmailMessagesXmlEndpoint.java @@ -0,0 +1,44 @@ +/* + * 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; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Email/Messages") +@ThreadSafe +public final class EmailMessagesXmlEndpoint extends EmailMessagesEndpoint { + public EmailMessagesXmlEndpoint() { + super(); + } + + @POST + public Response putEmailMessage(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return putEmailMessage(accountSid, data, MediaType.APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java new file mode 100644 index 0000000000..ec48348161 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java @@ -0,0 +1,277 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ExtensionsConfigurationDao; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.extension.api.ConfigurationException; +import org.restcomm.connect.extension.api.ExtensionConfiguration; +import org.restcomm.connect.http.converter.ExtensionConfigurationConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; + +import javax.annotation.PostConstruct; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +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.NOT_ACCEPTABLE; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +/** + * Created by gvagenas on 12/10/2016. + */ +public class ExtensionsConfigurationEndpoint extends SecuredEndpoint { + protected Configuration allConfiguration; + protected Configuration configuration; + protected Gson gson; + protected XStream xstream; + protected ExtensionsConfigurationDao extensionsConfigurationDao; + + public ExtensionsConfigurationEndpoint() { super(); } + + @PostConstruct + void init() { + allConfiguration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = allConfiguration.subset("runtime-settings"); + super.init(configuration); + extensionsConfigurationDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getExtensionsConfigurationDao(); + final ExtensionConfigurationConverter converter = new ExtensionConfigurationConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(ExtensionConfiguration.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new ExtensionConfigurationConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + /** + * Will be used to get configuration for extension + * @param extensionId + * @param responseType + * @return + */ + protected Response getConfiguration(final String extensionId, final Sid accountSid, final MediaType responseType) { + //Parameter "extensionId" could be the extension Sid or extension name. + + ExtensionConfiguration extensionConfiguration = null; + ExtensionConfiguration extensionAccountConfiguration = null; + Sid extensionSid = null; + String extensionName = null; + + if(Sid.pattern.matcher(extensionId).matches()){ + extensionSid = new Sid(extensionId); + } else { + extensionName = extensionId; + } + + if (Sid.pattern.matcher(extensionId).matches()) { + try { + extensionConfiguration = extensionsConfigurationDao.getConfigurationBySid(extensionSid); + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } else { + try { + extensionConfiguration = extensionsConfigurationDao.getConfigurationByName(extensionName); + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } + + if (accountSid!=null) { + if(extensionSid == null ){ + extensionSid = extensionConfiguration.getSid(); + } + try { + extensionAccountConfiguration = extensionsConfigurationDao.getAccountExtensionConfiguration(accountSid.toString(), extensionSid.toString()); + extensionConfiguration.setConfigurationData(extensionAccountConfiguration.getConfigurationData(), extensionAccountConfiguration.getConfigurationType()); + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } + + if (extensionConfiguration == null) { + return status(NOT_FOUND).build(); + } else { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(extensionConfiguration); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(extensionConfiguration), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private void validate(final MultivaluedMap data) throws NullPointerException { + if (!data.containsKey("ExtensionName")) { + throw new NullPointerException("Extension name can not be null."); + } else if (!data.containsKey("ConfigurationData")) { + throw new NullPointerException("ConfigurationData can not be null."); + } + } + + private ExtensionConfiguration createFrom(final MultivaluedMap data, final MediaType responseType) { + validate(data); + Sid sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION); + String extension = data.getFirst("ExtensionName"); + boolean enabled = Boolean.parseBoolean(data.getFirst("Enabled")); + Object configurationData = data.getFirst("ConfigurationData"); + ExtensionConfiguration.configurationType configurationType = null; + if (responseType.equals(APPLICATION_JSON_TYPE)) { + configurationType = ExtensionConfiguration.configurationType.JSON; + } else if (responseType.equals(APPLICATION_XML_TYPE)) { + configurationType = ExtensionConfiguration.configurationType.XML; + } + DateTime dateCreated = DateTime.now(); + DateTime dateUpdated = DateTime.now(); + ExtensionConfiguration extensionConfiguration = new ExtensionConfiguration(sid, extension, enabled, configurationData, configurationType, dateCreated, dateUpdated); + + return extensionConfiguration; + } + + protected Response postConfiguration(final MultivaluedMap data, final MediaType responseType) { + + Sid accountSid = null; + + String accountSidQuery = data.getFirst("AccountSid"); + if(accountSidQuery != null && !accountSidQuery.isEmpty()){ + accountSid = new Sid(accountSidQuery); + } + //if extension doesnt exist, add new extension + String extensionName = data.getFirst("ExtensionName"); + ExtensionConfiguration extensionConfiguration = extensionsConfigurationDao.getConfigurationByName(extensionName); + + if(extensionConfiguration==null){ + try { + extensionConfiguration = createFrom(data, responseType); + } catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + try { + extensionsConfigurationDao.addConfiguration(extensionConfiguration); + } catch (ConfigurationException exception) { + return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build(); + } + } + if (accountSid!=null) { + try { + Object configurationData = data.getFirst("ConfigurationData"); + // if accountSid exists, then this configuration is account specific, if it doesnt then its global config + extensionConfiguration.setConfigurationData(configurationData, extensionConfiguration.getConfigurationType()); + extensionsConfigurationDao.addAccountExtensionConfiguration(extensionConfiguration, accountSid); + } catch (ConfigurationException exception) { + return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build(); + } + } + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(extensionConfiguration), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(extensionConfiguration); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + + protected Response updateConfiguration(String extensionSid, MultivaluedMap data, MediaType responseType) { + + if (!Sid.pattern.matcher(extensionSid).matches()) { + return status(BAD_REQUEST).build(); + } + + ExtensionConfiguration extensionConfiguration = extensionsConfigurationDao.getConfigurationBySid(new Sid(extensionSid)); + if (extensionConfiguration == null) { + return status(NOT_FOUND).build(); + } + + ExtensionConfiguration updatedExtensionConfiguration = null; + Sid accountSid = null; + String accountSidQuery = data.getFirst("AccountSid"); + if(accountSidQuery != null && !accountSidQuery.isEmpty()){ + accountSid = new Sid(accountSidQuery); + } + + try { + updatedExtensionConfiguration = prepareUpdatedConfiguration(extensionConfiguration, data, responseType); + } catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + + try { + if (accountSid==null) { + extensionsConfigurationDao.updateConfiguration(updatedExtensionConfiguration); + } else { + extensionsConfigurationDao.updateAccountExtensionConfiguration(updatedExtensionConfiguration, accountSid); + } + } catch (ConfigurationException exception) { + return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build(); + } + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(updatedExtensionConfiguration), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(updatedExtensionConfiguration); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + + private ExtensionConfiguration prepareUpdatedConfiguration(ExtensionConfiguration existingExtensionConfiguration, MultivaluedMap data, MediaType responseType) { + validate(data); + Sid existingExtensionSid = existingExtensionConfiguration.getSid(); + String existingExtensionName = existingExtensionConfiguration.getExtensionName(); + boolean enabled = existingExtensionConfiguration.isEnabled(); + if (data.getFirst("Enabled") != null) { + enabled = Boolean.parseBoolean(data.getFirst("Enabled")); + } + Object configurationData = data.getFirst("ConfigurationData"); + DateTime dateCreated = existingExtensionConfiguration.getDateCreated(); + ExtensionConfiguration.configurationType configurationType = null; + if (responseType.equals(APPLICATION_JSON_TYPE)) { + configurationType = ExtensionConfiguration.configurationType.JSON; + } else if (responseType.equals(APPLICATION_XML_TYPE)) { + configurationType = ExtensionConfiguration.configurationType.XML; + } + + return new ExtensionConfiguration(existingExtensionSid, existingExtensionName, enabled, configurationData, configurationType, dateCreated ,DateTime.now()); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationJsonEndpoint.java new file mode 100644 index 0000000000..5ceb4cf5a6 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationJsonEndpoint.java @@ -0,0 +1,61 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.dao.Sid; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; + +/** + * Created by gvagenas on 12/10/2016. + */ +@Path("/ExtensionsConfiguration.json") +@RolesAllowed(SUPER_ADMIN_ROLE) +public class ExtensionsConfigurationJsonEndpoint extends ExtensionsConfigurationEndpoint { + + @Path("/{extensionId}") + @GET + public Response getConfigurationAsJson(@PathParam("extensionId") final String extension, @QueryParam("AccountSid") Sid accountSid) { + return getConfiguration(extension, accountSid, APPLICATION_JSON_TYPE); + } + + @POST + public Response postConfigurationAsJson(final MultivaluedMap data) { + return postConfiguration(data, APPLICATION_JSON_TYPE); + } + + @Path("/{extensionSid}") + @POST + public Response updateConfigurationAsJson(@PathParam("extensionSid") final String extensionSid, + final MultivaluedMap data) { + return updateConfiguration(extensionSid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationXmlEndpoint.java new file mode 100644 index 0000000000..ede1ea96a5 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationXmlEndpoint.java @@ -0,0 +1,62 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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; + +/** + * Created by gvagenas on 12/10/2016. + */ + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.dao.Sid; + +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; + +@Path("/ExtensionsConfiguration") +@RolesAllowed(SUPER_ADMIN_ROLE) +public class ExtensionsConfigurationXmlEndpoint extends ExtensionsConfigurationEndpoint { + + @Path("/{extensionId}") + @GET + public Response getConfigurationAsXml(@PathParam("extensionId") final String extension, @QueryParam("AccountSid") Sid accountSid) { + return getConfiguration(extension, accountSid, APPLICATION_XML_TYPE); + } + + @POST + public Response postConfigurationAsXml(final MultivaluedMap data) { + return postConfiguration(data, APPLICATION_XML_TYPE); + } + + @Path("/{extensionSid}") + @POST + public Response updateConfigurationAsXml(@PathParam("extensionSid") final String extensionSid, + final MultivaluedMap data) { + return updateConfiguration(extensionSid, data, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysEndpoint.java new file mode 100644 index 0000000000..62b5d3e0f3 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysEndpoint.java @@ -0,0 +1,198 @@ +package org.restcomm.connect.http; + +import akka.actor.ActorRef; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.GatewaysDao; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.dao.entities.GatewayList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.GatewayConverter; +import org.restcomm.connect.http.converter.GatewayListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.telephony.api.RegisterGateway; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.net.URI; +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.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +@ThreadSafe +public class GatewaysEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected GatewaysDao dao; + protected Gson gson; + protected XStream xstream; + private ActorRef proxyManager; + + public GatewaysEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getGatewaysDao(); + final GatewayConverter converter = new GatewayConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Gateway.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new GatewayListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + proxyManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.proxy.ProxyManager"); + } + + private Gateway createFrom(final MultivaluedMap data) { + final Gateway.Builder builder = Gateway.builder(); + final Sid sid = Sid.generate(Sid.Type.GATEWAY); + builder.setSid(sid); + String friendlyName = data.getFirst("FriendlyName"); + if (friendlyName == null || friendlyName.isEmpty()) { + friendlyName = data.getFirst("UserName"); + } + builder.setFriendlyName(friendlyName); + builder.setPassword(data.getFirst("Password")); + builder.setProxy(data.getFirst("Proxy")); + final boolean register = Boolean.parseBoolean(data.getFirst("Register")); + builder.setRegister(register); + builder.setUserName(data.getFirst("UserName")); + final int ttl = Integer.parseInt(data.getFirst("TTL")); + builder.setTimeToLive(ttl); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(getApiVersion(data)).append("/Management/").append("Gateways/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + protected Response getGateway(final String accountSid, final String sid, final MediaType responseType) { + final Gateway gateway = dao.getGateway(new Sid(sid)); + if (gateway == null) { + return status(NOT_FOUND).build(); + } else { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(gateway); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(gateway), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getGateways(final String accountSid, final MediaType responseType) { + final List gateways = dao.getGateways(); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new GatewayList(gateways)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(gateways), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response putGateway(final String accountSid, final MultivaluedMap data, final MediaType responseType) { + + try { + validate(data); + } catch (final RuntimeException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + final Gateway gateway = createFrom(data); + dao.addGateway(gateway); + if (proxyManager == null) { + proxyManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.proxy.ProxyManager"); + } + proxyManager.tell(new RegisterGateway(gateway), null); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(gateway); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(gateway), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response updateGateway(final String accountSid, final String sid, final MultivaluedMap data, final MediaType responseType) { + + Gateway gateway = dao.getGateway(new Sid(sid)); + if (gateway == null) { + return status(NOT_FOUND).build(); + } else { + dao.updateGateway(update(gateway, data)); + gateway = dao.getGateway(new Sid(sid)); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(gateway); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(gateway), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private void validate(final MultivaluedMap data) { + if (!data.containsKey("UserName")) { + throw new NullPointerException("UserName can not be null."); + } else if (!data.containsKey("Password")) { + throw new NullPointerException("Password can not be null."); + } else if (!data.containsKey("Proxy")) { + throw new NullPointerException("The Proxy can not be null"); + } else if (!data.containsKey("Register")) { + throw new NullPointerException("Register must be true or false"); + } + } + + private Gateway update(final Gateway gateway, final MultivaluedMap data) { + Gateway result = gateway; + if (data.containsKey("FriendlyName")) { + result = result.setFriendlyName(data.getFirst("FriendlyName")); + } + if (data.containsKey("UserName")) { + result = result.setUserName(data.getFirst("UserName")); + } + if (data.containsKey("Password")) { + result = result.setPassword(data.getFirst("Password")); + } + if (data.containsKey("Proxy")) { + result = result.setProxy(data.getFirst("Proxy")); + } + if (data.containsKey("Register")) { + result = result.setRegister(Boolean.parseBoolean("Register")); + } + if (data.containsKey("TTL")) { + result = result.setTimeToLive(Integer.parseInt(data.getFirst("TTL"))); + } + return result; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysJsonEndpoint.java new file mode 100644 index 0000000000..e4bd79b2cd --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysJsonEndpoint.java @@ -0,0 +1,55 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.*; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Management/Gateways.json") +@ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) +public class GatewaysJsonEndpoint extends GatewaysEndpoint { + public GatewaysJsonEndpoint() { + super(); + } + + @GET + public Response getGateways(@PathParam("accountSid") final String accountSid) { + return getGateways(accountSid, APPLICATION_JSON_TYPE); + } + + @POST + public Response putGateway(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return putGateway(accountSid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysXmlEndpoint.java new file mode 100644 index 0000000000..e64acec386 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GatewaysXmlEndpoint.java @@ -0,0 +1,113 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.*; +import static javax.ws.rs.core.Response.*; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Management/Gateways") +@ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) +public final class GatewaysXmlEndpoint extends GatewaysEndpoint { + public GatewaysXmlEndpoint() { + super(); + } + + private Response deleteGateway(final String accountSid, final String sid) { + secure(super.accountsDao.getAccount(accountSid), "RestComm:Modify:Gateways"); + dao.removeGateway(new Sid(sid)); + return ok().build(); + } + + @Path("/{sid}.json") + @DELETE + public Response deleteGatewayAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return deleteGateway(accountSid, sid); + } + + @Path("/{sid}") + @DELETE + public Response deleteGatewayAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return deleteGateway(accountSid, sid); + } + + @Path("/{sid}.json") + @GET + public Response getGatewayAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getGateway(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @GET + public Response getGatewayAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getGateway(accountSid, sid, APPLICATION_XML_TYPE); + } + + @GET + public Response getGatewaysList(@PathParam("accountSid") final String accountSid) { + return getGateways(accountSid, APPLICATION_XML_TYPE); + } + + @POST + public Response createGateway(@PathParam("accountSid") final String accountSid, final MultivaluedMap data) { + return putGateway(accountSid, data, APPLICATION_XML_TYPE); + } + + @Path("/{sid}.json") + @POST + public Response updateGatewayAsJsonPost(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGateway(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}.json") + @PUT + public Response updateGatewayAsJsonPut(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGateway(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @POST + public Response updateGatewayAsXmlPost(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGateway(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @Path("/{sid}") + @PUT + public Response updateGatewayAsXmlPut(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGateway(accountSid, sid, data, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationEndpoint.java new file mode 100644 index 0000000000..ed68ba1901 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationEndpoint.java @@ -0,0 +1,763 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +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.*; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.util.Arrays; +// import java.util.HashMap; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +// import org.apache.http.auth.AuthScope; +// import org.apache.http.auth.Credentials; +// import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.GeolocationDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.dao.entities.Geolocation.GeolocationType; +import org.restcomm.connect.dao.entities.GeolocationList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.http.converter.ClientListConverter; +import org.restcomm.connect.http.converter.GeolocationConverter; +import org.restcomm.connect.http.converter.GeolocationListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.commons.util.StringUtils; + +import org.apache.commons.configuration.Configuration; +// import org.apache.http.HttpException; +import org.apache.log4j.Logger; +// import org.apache.shiro.authz.AuthorizationException; +import org.joda.time.DateTime; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +/** + * @author Fernando Mendioroz + * + */ +@NotThreadSafe +public abstract class GeolocationEndpoint extends SecuredEndpoint { + + @Context + protected ServletContext context; + protected Configuration configuration; + protected GeolocationDao dao; + protected Gson gson; + protected XStream xstream; + protected AccountsDao accountsDao; + private static final Logger logger = Logger.getLogger(GeolocationEndpoint.class); + private static final String ImmediateGT = Geolocation.GeolocationType.Immediate.toString(); + private static final String NotificationGT = Geolocation.GeolocationType.Notification.toString(); + private String cause; + private String rStatus; + + private static enum responseStatus { + Queued("queued"), Sent("sent"), Processing("processing"), Successful("successful"), PartiallySuccessful( + "partially-successful"), LastKnown("last-known"), Failed("failed"), Unauthorized("unauthorized"), Rejected( + "rejected"); + + private final String rs; + + private responseStatus(final String rs) { + this.rs = rs; + } + + @Override + public String toString() { + return rs; + } + } + + public GeolocationEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + dao = storage.getGeolocationDao(); + accountsDao = storage.getAccountsDao(); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + final GeolocationConverter converter = new GeolocationConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Geolocation.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new ClientListConverter(configuration)); + xstream.registerConverter(new GeolocationListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + protected Response getGeolocation(final String accountSid, final String sid, final MediaType responseType) { + Account account; + try { + secure(account = accountsDao.getAccount(accountSid), "RestComm:Read:Geolocation"); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + // final Geolocation geolocation = dao.getGeolocation(new Sid(sid)); + Geolocation geolocation = null; + if (Sid.pattern.matcher(sid).matches()) { + geolocation = dao.getGeolocation(new Sid(sid)); + } + if (geolocation == null) { + return status(NOT_FOUND).build(); + } else { + try { + secure(account, geolocation.getAccountSid(), SecuredType.SECURED_APP); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(geolocation); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(geolocation), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getGeolocations(final String accountSid, final MediaType responseType) { + Account account; + try { + account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Read:Geolocation", SecuredType.SECURED_APP); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + final List geolocations = dao.getGeolocations(new Sid(accountSid)); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new GeolocationList(geolocations)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(geolocations), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response deleteGeolocation(final String accountSid, final String sid) { + Account account; + try { + secure(account = accountsDao.getAccount(accountSid), "RestComm:Delete:Geolocation"); + Geolocation geolocation = dao.getGeolocation(new Sid(sid)); + if (geolocation != null) { + secure(account, geolocation.getAccountSid(), SecuredType.SECURED_APP); + } + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + dao.removeGeolocation(new Sid(sid)); + return ok().build(); + } + + public Response putGeolocation(final String accountSid, final MultivaluedMap data, + GeolocationType geolocationType, final MediaType responseType) { + Account account; + try { + account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Create:Geolocation", SecuredType.SECURED_APP); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + + try { + validate(data, geolocationType); + } catch (final NullPointerException nullPointerException) { + // API compliance check regarding missing mandatory parameters + return status(BAD_REQUEST).entity(nullPointerException.getMessage()).build(); + } catch (final IllegalArgumentException illegalArgumentException) { + // API compliance check regarding malformed parameters + cause = illegalArgumentException.getMessage(); + rStatus = responseStatus.Failed.toString(); + } catch (final UnsupportedOperationException unsupportedOperationException) { + // API compliance check regarding parameters not allowed for Immediate type of Geolocation + return status(BAD_REQUEST).entity(unsupportedOperationException.getMessage()).build(); + } + + /*********************************************/ + /*** Query GMLC for Location Data, stage 1 ***/ + /*********************************************/ + try { + String targetMSISDN = data.getFirst("DeviceIdentifier"); + Configuration gmlcConf = configuration.subset("gmlc"); + String gmlcURI = gmlcConf.getString("gmlc-uri"); + // Authorization for further stage of the project + String gmlcUser = gmlcConf.getString("gmlc-user"); + String gmlcPassword = gmlcConf.getString("gmlc-password"); + // Credentials credentials = new UsernamePasswordCredentials(gmlcUser, gmlcPassword); + URL url = new URL(gmlcURI + targetMSISDN); + HttpClient client = HttpClientBuilder.create().build(); + HttpGet request = new HttpGet(String.valueOf(url)); + // Authorization for further stage of the project + request.addHeader("User-Agent", gmlcUser); + request.addHeader("User-Password", gmlcPassword); + HttpResponse response = client.execute(request); + final HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream stream = entity.getContent(); + try { + BufferedReader br = new BufferedReader( + new InputStreamReader(stream)); + String gmlcResponse = null; + while (null != (gmlcResponse = br.readLine())) { + List items = Arrays.asList(gmlcResponse.split("\\s*,\\s*")); + if (logger.isInfoEnabled()) { + logger.info("Data retrieved from GMLC: " + items.toString()); + } + for (String item : items) { + for (int i = 0; i < items.size(); i++) { + if (item.contains("mcc")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("MobileCountryCode", token); + } + if (item.contains("mnc")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("MobileNetworkCode", token); + } + if (item.contains("lac")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("LocationAreaCode", token); + } + if (item.contains("cellid")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("CellId", token); + } + if (item.contains("aol")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("LocationAge", token); + } + if (item.contains("vlrNumber")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("NetworkEntityAddress", token); + } + if (item.contains("latitude")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("DeviceLatitude", token); + } + if (item.contains("longitude")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("DeviceLongitude", token); + } + if (item.contains("civicAddress")) { + String token = item.substring(item.lastIndexOf("=") + 1); + data.putSingle("FormattedAddress", token); + } + } + } + if (gmlcURI != null && gmlcResponse != null) { + // For debugging/logging purposes only + if (logger.isDebugEnabled()) { + logger.debug("Geolocation data of " + targetMSISDN + " retrieved from GMCL at: " + gmlcURI); + logger.debug("MCC (Mobile Country Code) = " + getInteger("MobileCountryCode", data)); + logger.debug("MNC (Mobile Network Code) = " + data.getFirst("MobileNetworkCode")); + logger.debug("LAC (Location Area Code) = " + data.getFirst("LocationAreaCode")); + logger.debug("CI (Cell ID) = " + data.getFirst("CellId")); + logger.debug("AOL (Age of Location) = " + getInteger("LocationAge", data)); + logger.debug("NNN (Network Node Number/Address) = " + +getLong("NetworkEntityAddress", data)); + logger.debug("Devide Latitude = " + data.getFirst("DeviceLatitude")); + logger.debug("Devide Longitude = " + data.getFirst("DeviceLongitude")); + logger.debug("Civic Address = " + data.getFirst("FormattedAddress")); + } + } + } + } finally { + stream.close(); + } + } + + } catch (Exception ex) { + if (logger.isInfoEnabled()) { + logger.info("Problem while trying to retrieve data from GMLC"); + } + return status(INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + + Geolocation geolocation = createFrom(new Sid(accountSid), data, geolocationType); + + if (geolocation.getResponseStatus() != null + && geolocation.getResponseStatus().equals(responseStatus.Rejected.toString())) { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(geolocation); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(geolocation), APPLICATION_JSON).build(); + } else { + return null; + } + } else { + + dao.addGeolocation(geolocation); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(geolocation); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(geolocation), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private void validate(final MultivaluedMap data, Geolocation.GeolocationType glType) + throws RuntimeException { + + // ** Validation of Geolocation POST requests with valid type **/ + if (!glType.toString().equals(ImmediateGT) && !glType.toString().equals(NotificationGT)) { + throw new NullPointerException("Geolocation Type can not be null, but either \"Immediate\" or \"Notification\"."); + } + + // *** DeviceIdentifier can not be null ***/ + if (!data.containsKey("DeviceIdentifier")) { + throw new NullPointerException("DeviceIdentifier value can not be null"); + } + + // *** StatusCallback can not be null ***/ + if (!data.containsKey("StatusCallback")) { + throw new NullPointerException("StatusCallback value can not be null"); + } + + // *** DesiredAccuracy must be API compliant: High, Average or Low***/ + if (data.containsKey("DesiredAccuracy")) { + String desiredAccuracy = data.getFirst("DesiredAccuracy"); + if (!desiredAccuracy.equalsIgnoreCase("High") && !desiredAccuracy.equalsIgnoreCase("Average") + && !desiredAccuracy.equalsIgnoreCase("Low")) { + throw new IllegalArgumentException("DesiredAccuracy value not API compliant"); + } + } + + // *** DeviceLatitude must be API compliant***/ + if (data.containsKey("DeviceLatitude")) { + String deviceLat = data.getFirst("DeviceLatitude"); + Boolean devLatWGS84 = validateGeoCoordinatesFormat(deviceLat); + if (!devLatWGS84) { + throw new IllegalArgumentException("DeviceLatitude not API compliant"); + } + } + + // *** DeviceLongitude must be API compliant***/ + if (data.containsKey("DeviceLongitude")) { + String deviceLong = data.getFirst("DeviceLongitude"); + Boolean devLongWGS84 = validateGeoCoordinatesFormat(deviceLong); + if (!devLongWGS84) { + throw new IllegalArgumentException("DeviceLongitude not API compliant"); + } + } + + // *** GeofenceEvent must belong to Notification type of Geolocation, not null and API compliant: in, out or in-out***/ + if (!data.containsKey("GeofenceEvent") && glType.toString().equals(NotificationGT)) { + throw new NullPointerException("GeofenceEvent value con not be null for Notification type of Geolocation"); + } else if (data.containsKey("GeofenceEvent") && !glType.toString().equals(NotificationGT)) { + throw new UnsupportedOperationException("GeofenceEvent only applies for Notification type of Geolocation"); + } else if (data.containsKey("GeofenceEvent") && glType.toString().equals(NotificationGT)) { + String geofenceEvent = data.getFirst("GeofenceEvent"); + if (!geofenceEvent.equalsIgnoreCase("in") && !geofenceEvent.equalsIgnoreCase("out") + && !geofenceEvent.equalsIgnoreCase("in-out")) { + throw new IllegalArgumentException("GeofenceEvent value not API compliant"); + } + } + + // *** EventGeofenceLatitude must belong to Notification type of Geolocation, not null and API compliant ***/ + if (!data.containsKey("EventGeofenceLatitude") && glType.toString().equals(NotificationGT)) { + throw new NullPointerException("EventGeofenceLatitude value con not be null for Notification type of Geolocation"); + } else if (data.containsKey("EventGeofenceLatitude") && !glType.toString().equals(NotificationGT)) { + throw new UnsupportedOperationException("EventGeofenceLatitude only applies for Notification type of Geolocation"); + } else if (data.containsKey("EventGeofenceLatitude") && glType.toString().equals(NotificationGT)) { + String eventGeofenceLat = data.getFirst("EventGeofenceLatitude"); + Boolean eventGeofenceLongWGS84 = validateGeoCoordinatesFormat(eventGeofenceLat); + if (!eventGeofenceLongWGS84) { + throw new IllegalArgumentException("EventGeofenceLatitude format not API compliant"); + } + } + + // *** EventGeofenceLongitude must belong to Notification type of Geolocation and must be API compliant ***/ + if (!data.containsKey("EventGeofenceLongitude") && glType.toString().equals(NotificationGT)) { + throw new NullPointerException("EventGeofenceLongitude value con not be null for Notification type of Geolocation"); + } else if (data.containsKey("EventGeofenceLongitude") && !glType.toString().equals(NotificationGT)) { + throw new UnsupportedOperationException("EventGeofenceLongitude only applies for Notification type of Geolocation"); + } else if (data.containsKey("EventGeofenceLongitude") && glType.toString().equals(NotificationGT)) { + String eventGeofenceLong = data.getFirst("EventGeofenceLongitude"); + Boolean eventGeofenceLongWGS84 = validateGeoCoordinatesFormat(eventGeofenceLong); + if (!eventGeofenceLongWGS84) { + throw new IllegalArgumentException("EventGeofenceLongitude format not API compliant"); + } + } + + // *** GeofenceRange can not be null in Notification type of Geolocation***/ + if (!data.containsKey("GeofenceRange") && glType.toString().equals(NotificationGT)) { + throw new NullPointerException("GeofenceRange value con not be null for Notification type of Geolocation"); + } else if (data.containsKey("GeofenceRange") && !glType.toString().equals(NotificationGT)) { + throw new UnsupportedOperationException("GeofenceRange only applies for Notification type of Geolocation"); + } + + // *** LocationTimestamp must be API compliant: DateTime format only***/ + try { + if (data.containsKey("LocationTimestamp")) { + @SuppressWarnings("unused") + DateTime locationTimestamp = getDateTime("LocationTimestamp", data); + } + } catch (IllegalArgumentException exception) { + throw new IllegalArgumentException("LocationTimestamp value is not API compliant"); + } + } + + private Geolocation createFrom(final Sid accountSid, final MultivaluedMap data, + Geolocation.GeolocationType glType) { + + if (rStatus != null && rStatus.equals(responseStatus.Failed.toString())) { + Geolocation gl = buildFailedGeolocation(accountSid, data, glType); + return gl; + } else { + Geolocation gl = buildGeolocation(accountSid, data, glType); + return gl; + } + } + + private Geolocation buildGeolocation(final Sid accountSid, final MultivaluedMap data, + Geolocation.GeolocationType glType) { + final Geolocation.Builder builder = Geolocation.builder(); + final Sid sid = Sid.generate(Sid.Type.GEOLOCATION); + String geoloctype = glType.toString(); + builder.setSid(sid); + DateTime currentDateTime = DateTime.now(); + builder.setDateUpdated(currentDateTime); + builder.setAccountSid(accountSid); + builder.setSource(data.getFirst("Source")); + builder.setDeviceIdentifier(data.getFirst("DeviceIdentifier")); + builder.setGeolocationType(glType); + builder.setResponseStatus(data.getFirst("ResponseStatus")); + builder.setCause(data.getFirst("Cause")); + builder.setCellId(data.getFirst("CellId")); + builder.setLocationAreaCode(data.getFirst("LocationAreaCode")); + builder.setMobileCountryCode(getInteger("MobileCountryCode", data)); + builder.setMobileNetworkCode(data.getFirst("MobileNetworkCode")); + builder.setNetworkEntityAddress(getLong("NetworkEntityAddress", data)); + builder.setAgeOfLocationInfo(getInteger("LocationAge", data)); + builder.setDeviceLatitude(data.getFirst("DeviceLatitude")); + builder.setDeviceLongitude(data.getFirst("DeviceLongitude")); + builder.setAccuracy(getLong("Accuracy", data)); + builder.setPhysicalAddress(data.getFirst("PhysicalAddress")); + builder.setInternetAddress(data.getFirst("InternetAddress")); + builder.setFormattedAddress(data.getFirst("FormattedAddress")); + builder.setLocationTimestamp(getDateTime("LocationTimestamp", data)); + builder.setEventGeofenceLatitude(data.getFirst("EventGeofenceLatitude")); + builder.setEventGeofenceLongitude(data.getFirst("EventGeofenceLongitude")); + builder.setRadius(getLong("Radius", data)); + builder.setGeolocationPositioningType(data.getFirst("GeolocationPositioningType")); + builder.setLastGeolocationResponse(data.getFirst("LastGeolocationResponse")); + builder.setApiVersion(getApiVersion(data)); + String rootUri = configuration.getString("root-uri"); + rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); + final StringBuilder buffer = new StringBuilder(); + buffer.append(rootUri).append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Geolocation/" + geoloctype + "/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + private Geolocation buildFailedGeolocation(final Sid accountSid, final MultivaluedMap data, + Geolocation.GeolocationType glType) { + final Geolocation.Builder builder = Geolocation.builder(); + final Sid sid = Sid.generate(Sid.Type.GEOLOCATION); + String geoloctype = glType.toString(); + builder.setSid(sid); + DateTime currentDateTime = DateTime.now(); + builder.setDateUpdated(currentDateTime); + builder.setAccountSid(accountSid); + builder.setSource(data.getFirst("Source")); + builder.setDeviceIdentifier(data.getFirst("DeviceIdentifier")); + builder.setResponseStatus(rStatus); + builder.setGeolocationType(glType); + builder.setCause(cause); + builder.setApiVersion(getApiVersion(data)); + String rootUri = configuration.getString("root-uri"); + rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); + final StringBuilder buffer = new StringBuilder(); + buffer.append(rootUri).append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Geolocation/" + geoloctype + "/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + protected Response updateGeolocation(final String accountSid, final String sid, final MultivaluedMap data, + final MediaType responseType) { + Account account; + try { + secure(account = accountsDao.getAccount(accountSid), "RestComm:Modify:Geolocation"); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + Geolocation geolocation = dao.getGeolocation(new Sid(sid)); + if (geolocation == null) { + return status(NOT_FOUND).build(); + } else { + try { + secure(account, geolocation.getAccountSid(), SecuredType.SECURED_APP); + } catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } catch (final Exception exception) { + return status(UNAUTHORIZED).build(); + } + + geolocation = update(geolocation, data); + dao.updateGeolocation(geolocation); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(geolocation); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(geolocation), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + private Geolocation update(final Geolocation geolocation, final MultivaluedMap data) { + + Geolocation updatedGeolocation = geolocation; + // *** Set of parameters with provided data for Geolocation update***// + if (data.containsKey("Source")) { + updatedGeolocation = updatedGeolocation.setSource(data.getFirst("Source")); + + } + + if (data.containsKey("DeviceIdentifier")) { + updatedGeolocation = updatedGeolocation.setDeviceIdentifier(data.getFirst("DeviceIdentifier")); + } + + if (data.containsKey("ResponseStatus")) { + updatedGeolocation = updatedGeolocation.setResponseStatus(data.getFirst("ResponseStatus")); + updatedGeolocation = updatedGeolocation.setDateUpdated(DateTime.now()); + if (data.containsKey("Cause") && (updatedGeolocation.getResponseStatus().equals(responseStatus.Rejected.toString()) + || updatedGeolocation.getResponseStatus().equals(responseStatus.Unauthorized.toString()) + || updatedGeolocation.getResponseStatus().equals(responseStatus.Failed.toString()))) { + updatedGeolocation = updatedGeolocation.setCause(data.getFirst("Cause")); + // cause is set to null if responseStatus is not rejected, failed or unauthorized + } + if (!updatedGeolocation.getResponseStatus().equals(responseStatus.Rejected.toString()) + || !updatedGeolocation.getResponseStatus().equals(responseStatus.Unauthorized.toString()) + || !updatedGeolocation.getResponseStatus().equals(responseStatus.Failed.toString())) { + updatedGeolocation = updatedGeolocation.setCause(null); + // cause is set to null if responseStatus is not rejected, failed or unauthorized + } + } + + if (updatedGeolocation.getResponseStatus() != null + && (!updatedGeolocation.getResponseStatus().equals(responseStatus.Unauthorized.toString()) + || !updatedGeolocation.getResponseStatus().equals(responseStatus.Failed.toString()))) { + updatedGeolocation = updatedGeolocation.setCause(null); + // "Cause" is set to null if "ResponseStatus" is not null and is neither "rejected", "unauthorized" nor "failed" + } + + if (data.containsKey("CellId")) { + updatedGeolocation = updatedGeolocation.setCellId(data.getFirst("CellId")); + } + + if (data.containsKey("LocationAreaCode")) { + updatedGeolocation = updatedGeolocation.setLocationAreaCode(data.getFirst("LocationAreaCode")); + } + + if (data.containsKey("MobileCountryCode")) { + updatedGeolocation = updatedGeolocation.setMobileCountryCode(getInteger("MobileCountryCode", data)); + } + + if (data.containsKey("MobileNetworkCode")) { + updatedGeolocation = updatedGeolocation.setMobileNetworkCode(data.getFirst("MobileNetworkCode")); + } + + if (data.containsKey("NetworkEntityAddress")) { + updatedGeolocation = updatedGeolocation.setNetworkEntityAddress(getLong("NetworkEntityAddress", data)); + } + + if (data.containsKey("LocationAge")) { + updatedGeolocation = updatedGeolocation.setAgeOfLocationInfo(getInteger("LocationAge", data)); + } + + if (data.containsKey("DeviceLatitude")) { + String deviceLat = data.getFirst("DeviceLatitude"); + Boolean deviceLatWGS84 = validateGeoCoordinatesFormat(deviceLat); + if (!deviceLatWGS84) { + return buildFailedGeolocationUpdate(geolocation, data, geolocation.getGeolocationType(), + responseStatus.Failed.toString(), "DeviceLatitude format not API compliant"); + } else { + updatedGeolocation = updatedGeolocation.setDeviceLatitude(deviceLat); + } + } + + if (data.containsKey("DeviceLongitude")) { + updatedGeolocation = updatedGeolocation.setDeviceLongitude(data.getFirst("DeviceLongitude")); + String deviceLong = data.getFirst("DeviceLongitude"); + Boolean deviceLongGS84 = validateGeoCoordinatesFormat(deviceLong); + if (!deviceLongGS84) { + return buildFailedGeolocationUpdate(geolocation, data, geolocation.getGeolocationType(), + responseStatus.Failed.toString(), "DeviceLongitude format not API compliant"); + } else { + updatedGeolocation = updatedGeolocation.setDeviceLongitude(deviceLong); + } + } + + if (data.containsKey("Accuracy")) { + updatedGeolocation = updatedGeolocation.setAccuracy(getLong("Accuracy", data)); + } + + if (data.containsKey("PhysicalAddress")) { + updatedGeolocation = updatedGeolocation.setPhysicalAddress(data.getFirst("PhysicalAddress")); + } + + if (data.containsKey("InternetAddress")) { + updatedGeolocation = updatedGeolocation.setInternetAddress(data.getFirst("InternetAddress")); + } + + if (data.containsKey("FormattedAddress")) { + updatedGeolocation = updatedGeolocation.setFormattedAddress(data.getFirst("FormattedAddress")); + } + + if (data.containsKey("LocationTimestamp")) { + updatedGeolocation = updatedGeolocation.setLocationTimestamp(getDateTime("LocationTimestamp", data)); + } + + if (data.containsKey("EventGeofenceLatitude") && geolocation.getGeolocationType().toString().equals(NotificationGT)) { + String eventGeofenceLat = data.getFirst("EventGeofenceLatitude"); + Boolean eventGeofenceLatWGS84 = validateGeoCoordinatesFormat(eventGeofenceLat); + if (!eventGeofenceLatWGS84) { + return buildFailedGeolocationUpdate(geolocation, data, geolocation.getGeolocationType(), + responseStatus.Failed.toString(), "EventGeofenceLatitude format not API compliant"); + } else { + updatedGeolocation = updatedGeolocation.setEventGeofenceLatitude(eventGeofenceLat); + } + } + + if (data.containsKey("EventGeofenceLongitude") && geolocation.getGeolocationType().toString().equals(NotificationGT)) { + String eventGeofenceLong = data.getFirst("EventGeofenceLongitude"); + Boolean eventGeofenceLongWGS84 = validateGeoCoordinatesFormat(eventGeofenceLong); + if (!eventGeofenceLongWGS84) { + return buildFailedGeolocationUpdate(geolocation, data, geolocation.getGeolocationType(), + responseStatus.Failed.toString(), "EventGeofenceLongitude format not API compliant"); + } else { + updatedGeolocation = updatedGeolocation.setEventGeofenceLongitude(eventGeofenceLong); + } + } + + if (data.containsKey("Radius") && geolocation.getGeolocationType().toString().equals(NotificationGT)) { + updatedGeolocation = updatedGeolocation.setRadius(getLong("Radius", data)); + } + + if (data.containsKey("GeolocationPositioningType")) { + updatedGeolocation = updatedGeolocation.setGeolocationPositioningType(data.getFirst("GeolocationPositioningType")); + } + + if (data.containsKey("LastGeolocationResponse")) { + updatedGeolocation = updatedGeolocation.setLastGeolocationResponse(data.getFirst("LastGeolocationResponse")); + } + + DateTime thisDateTime = DateTime.now(); + updatedGeolocation = updatedGeolocation.setDateUpdated(thisDateTime); + return updatedGeolocation; + } + + private Geolocation buildFailedGeolocationUpdate(Geolocation geolocation, final MultivaluedMap data, + Geolocation.GeolocationType glType, String responseStatus, String wrongUpdateCause) { + final Sid accountSid = geolocation.getAccountSid(); + final Sid sid = geolocation.getSid(); + final Geolocation.Builder builder = Geolocation.builder(); + String geoloctype = glType.toString(); + DateTime currentDateTime = DateTime.now(); + builder.setSid(sid); + builder.setDateUpdated(currentDateTime); + builder.setAccountSid(accountSid); + builder.setResponseStatus(responseStatus); + builder.setCause(wrongUpdateCause); + builder.setSource(data.getFirst("Source")); + builder.setDeviceIdentifier(data.getFirst("DeviceIdentifier")); + builder.setGeolocationType(glType); + builder.setApiVersion(getApiVersion(data)); + String rootUri = configuration.getString("root-uri"); + rootUri = StringUtils.addSuffixIfNotPresent(rootUri, "/"); + final StringBuilder buffer = new StringBuilder(); + buffer.append(rootUri).append(getApiVersion(data)).append("/Accounts/").append(accountSid.toString()) + .append("/Geolocation/" + geoloctype + "/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + private boolean validateGeoCoordinatesFormat(String coordinates) { + + String degrees = "\\u00b0"; + String minutes = "'"; + Boolean WGS84_validation; + Boolean pattern1 = coordinates.matches("[NWSE]{1}\\d{1,3}\\s\\d{1,2}\\s\\d{1,2}\\.\\d{1,2}$"); + Boolean pattern2 = coordinates.matches("\\d{1,3}\\s\\d{1,2}\\s\\d{1,2}\\.\\d{1,2}[NWSE]{1}$"); + Boolean pattern3 = coordinates.matches("\\d{1,3}[" + degrees + "]\\d{1,3}[" + minutes + "]\\d{1,2}\\.\\d{1,2}[" + + minutes + "][" + minutes + "][NWSE]{1}$"); + Boolean pattern4 = coordinates.matches("[NWSE]{1}\\d{1,3}[" + degrees + "]\\d{1,3}[" + minutes + "]\\d{1,2}\\.\\d{1,2}[" + + minutes + "][" + minutes + "]$"); + Boolean pattern5 = coordinates.matches("\\d{1,3}\\s\\d{1,2}\\s\\d{1,2}\\.\\d{1,2}$"); + Boolean pattern6 = coordinates.matches("-?\\d{1,3}\\s\\d{1,2}\\s\\d{1,2}\\.\\d{1,2}$"); + Boolean pattern7 = coordinates.matches("-?\\d+(\\.\\d+)?"); + + if (pattern1 || pattern2 || pattern3 || pattern4 || pattern5 || pattern6 || pattern7) { + WGS84_validation = true; + return WGS84_validation; + } else { + WGS84_validation = false; + return WGS84_validation; + } + } + +} + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationJsonEndpoint.java new file mode 100644 index 0000000000..05467d25a9 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationJsonEndpoint.java @@ -0,0 +1,50 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author Fernando Mendioroz + * + */ +@Path("/Accounts/{accountSid}/Geolocation.json") +@ThreadSafe +public class GeolocationJsonEndpoint extends GeolocationEndpoint { + + public GeolocationJsonEndpoint() { + super(); + } + + @GET + public Response getGeolocationsAsJson(@PathParam("accountSid") final String accountSid) { + return getGeolocations(accountSid, APPLICATION_JSON_TYPE); + } +} + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationXmlEndpoint.java new file mode 100644 index 0000000000..929908bc2f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/GeolocationXmlEndpoint.java @@ -0,0 +1,205 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Geolocation; + +/** + * @author Fernando Mendioroz + * + */ +@Path("/Accounts/{accountSid}/Geolocation") +@ThreadSafe +public final class GeolocationXmlEndpoint extends GeolocationEndpoint { + + public GeolocationXmlEndpoint() { + super(); + } + + /*******************************************/ + // *** Immediate type of Geolocation ***// + /*******************************************/ + + @Path("/Immediate/{sid}.json") + @DELETE + public Response deleteImmediateGeolocationAsJson(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return deleteGeolocation(accountSid, sid); + } + + @Path("/Immediate/{sid}") + @DELETE + public Response deleteImmediateGeolocationAsXml(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return deleteGeolocation(accountSid, sid); + } + + @Path("/Immediate/{sid}.json") + @GET + public Response getImmediateGeolocationAsJson(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return getGeolocation(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/Immediate/{sid}") + @GET + public Response getImmediateGeolocationAsXml(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return getGeolocation(accountSid, sid, APPLICATION_XML_TYPE); + } + + @Path("/Immediate.json") + @POST + public Response putImmediateGeolocationJsonPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return putGeolocation(accountSid, data, Geolocation.GeolocationType.Immediate, APPLICATION_JSON_TYPE); + } + + @Path("/Immediate/{sid}.json") + @POST + public Response updateImmediateGeolocationAsJsonPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/Immediate/{sid}.json") + @PUT + public Response updateImmediateGeolocationAsJsonPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/Immediate") + @POST + public Response putImmediateGeolocationXmlPost(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return putGeolocation(accountSid, data, Geolocation.GeolocationType.Immediate, APPLICATION_XML_TYPE); + } + + @Path("/Immediate/{sid}") + @POST + public Response putImmediateGeolocationAsXmlPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @Path("/Immediate/{sid}") + @PUT + public Response updateImmediateGeolocationAsXmlPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + /*******************************************/ + // *** Notification type of Geolocation ***// + /*******************************************/ + + @Path("/Notification/{sid}.json") + @DELETE + public Response deleteNotificationGeolocationAsJson(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return deleteGeolocation(accountSid, sid); + } + + @Path("/Notification/{sid}") + @DELETE + public Response deleteNotificationGeolocationAsXml(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return deleteGeolocation(accountSid, sid); + } + + @Path("/Notification/{sid}.json") + @GET + public Response getNotificationGeolocationAsJson(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return getGeolocation(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/Notification/{sid}") + @GET + public Response getNotificationGeolocationAsXml(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid) { + return getGeolocation(accountSid, sid, APPLICATION_XML_TYPE); + } + + @Path("/Notification.json") + @POST + public Response putNotificationGeolocationJsonPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return putGeolocation(accountSid, data, Geolocation.GeolocationType.Notification, APPLICATION_JSON_TYPE); + } + + @Path("/Notification/{sid}.json") + @POST + public Response updateNotificationGeolocationAsJsonPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/Notification/{sid}.json") + @PUT + public Response updateNotificationGeolocationAsJsonPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_JSON_TYPE); + } + + @Path("/Notification") + @POST + public Response putNotificationGeolocationXmlPost(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return putGeolocation(accountSid, data, Geolocation.GeolocationType.Notification, APPLICATION_XML_TYPE); + } + + @Path("/Notification/{sid}") + @POST + public Response putNotificationGeolocationAsXmlPost(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @Path("/Notification/{sid}") + @PUT + public Response updateNotificationGeolocationAsXmlPut(@PathParam("accountSid") final String accountSid, + @PathParam("sid") final String sid, final MultivaluedMap data) { + return updateGeolocation(accountSid, sid, data, APPLICATION_XML_TYPE); + } + + @GET + public Response getGeolocationsAsXml(@PathParam("accountSid") final String accountSid) { + return getGeolocations(accountSid, APPLICATION_XML_TYPE); + } + + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersEndpoint.java new file mode 100644 index 0000000000..29d7701cfd --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersEndpoint.java @@ -0,0 +1,759 @@ +/* + * 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; + +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.noContent; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static javax.ws.rs.core.Response.Status.FORBIDDEN; +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.OK; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.loader.ObjectInstantiationException; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberList; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.dao.entities.SearchFilterMode; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.http.converter.AvailableCountriesConverter; +import org.restcomm.connect.http.converter.AvailableCountriesList; +import org.restcomm.connect.http.converter.IncomingPhoneNumberConverter; +import org.restcomm.connect.http.converter.IncomingPhoneNumberListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.provisioning.number.api.PhoneNumberParameters; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManager; +import org.restcomm.connect.provisioning.number.api.PhoneNumberProvisioningManagerProvider; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.NumberParseException.ErrorType; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; +import com.thoughtworks.xstream.XStream; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author gvagenas@gmail.com + * @author jean.deruelle@telestax.com + * @author maria.farooq@telestax.com + */ +@NotThreadSafe +public abstract class IncomingPhoneNumbersEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected PhoneNumberProvisioningManager phoneNumberProvisioningManager; + protected IncomingPhoneNumberListConverter listConverter; + PhoneNumberParameters phoneNumberParameters; + String callbackPort = ""; + private IncomingPhoneNumbersDao dao; + private OrganizationsDao organizationsDao; + private XStream xstream; + protected Gson gson; + + public IncomingPhoneNumbersEndpoint() { + super(); + } + + @PostConstruct + public void init() throws ObjectInstantiationException { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + super.init(configuration.subset("runtime-settings")); + dao = storage.getIncomingPhoneNumbersDao(); + accountsDao = storage.getAccountsDao(); + organizationsDao = storage.getOrganizationsDao(); + + /* + phoneNumberProvisioningManager = (PhoneNumberProvisioningManager) context.getAttribute("PhoneNumberProvisioningManager"); + if(phoneNumberProvisioningManager == null) { + final String phoneNumberProvisioningManagerClass = configuration.getString("phone-number-provisioning[@class]"); + Configuration phoneNumberProvisioningConfiguration = configuration.subset("phone-number-provisioning"); + Configuration telestaxProxyConfiguration = configuration.subset("runtime-settings").subset("telestax-proxy"); + + phoneNumberProvisioningManager = (PhoneNumberProvisioningManager) new ObjectFactory(getClass().getClassLoader()) + .getObjectInstance(phoneNumberProvisioningManagerClass); + ContainerConfiguration containerConfiguration = new ContainerConfiguration(getOutboundInterfaces()); + phoneNumberProvisioningManager.init(phoneNumberProvisioningConfiguration, telestaxProxyConfiguration, containerConfiguration); + context.setAttribute("phoneNumberProvisioningManager", phoneNumberProvisioningManager); + } + */ + // get manager from context or create it if it does not exist + phoneNumberProvisioningManager = new PhoneNumberProvisioningManagerProvider(configuration, context).get(); + + Configuration callbackUrlsConfiguration = configuration.subset("phone-number-provisioning").subset("callback-urls"); + String voiceUrl = callbackUrlsConfiguration.getString("voice[@url]"); + if(voiceUrl != null && !voiceUrl.trim().isEmpty()) { + String[] voiceUrlArr = voiceUrl.split(":"); + if(voiceUrlArr != null && voiceUrlArr.length==2) + callbackPort = voiceUrlArr[1]; + } + phoneNumberParameters = new PhoneNumberParameters( + voiceUrl, + callbackUrlsConfiguration.getString("voice[@method]"), false, + callbackUrlsConfiguration.getString("sms[@url]"), + callbackUrlsConfiguration.getString("sms[@method]"), + callbackUrlsConfiguration.getString("fax[@url]"), + callbackUrlsConfiguration.getString("fax[@method]"), + callbackUrlsConfiguration.getString("ussd[@url]"), + callbackUrlsConfiguration.getString("ussd[@method]")); + + final IncomingPhoneNumberConverter converter = new IncomingPhoneNumberConverter(configuration); + listConverter = new IncomingPhoneNumberListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.serializeNulls(); + builder.registerTypeAdapter(IncomingPhoneNumber.class, converter); + builder.registerTypeAdapter(IncomingPhoneNumberList.class, listConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(listConverter); + xstream.registerConverter(new AvailableCountriesConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + + } + + private IncomingPhoneNumber createFrom(final Sid accountSid, final MultivaluedMap data, Sid organizationSid) { + final IncomingPhoneNumber.Builder builder = IncomingPhoneNumber.builder(); + final Sid sid = Sid.generate(Sid.Type.PHONE_NUMBER); + builder.setSid(sid); + builder.setAccountSid(accountSid); + String phoneNumber = data.getFirst("PhoneNumber"); + String cost = data.getFirst("Cost"); + builder.setPhoneNumber(phoneNumber); + builder.setFriendlyName(getFriendlyName(phoneNumber, data)); + if (data.containsKey("VoiceCapable")) { + builder.setVoiceCapable(Boolean.parseBoolean(data.getFirst("VoiceCapable"))); + } + if (data.containsKey("SmsCapable")) { + builder.setSmsCapable(Boolean.parseBoolean(data.getFirst("SmsCapable"))); + } + if (data.containsKey("MmsCapable")) { + builder.setMmsCapable(Boolean.parseBoolean(data.getFirst("MmsCapable"))); + } + if (data.containsKey("FaxCapable")) { + builder.setFaxCapable(Boolean.parseBoolean(data.getFirst("FaxCapable"))); + } + if (data.containsKey("isSIP")) { + builder.setPureSip(Boolean.parseBoolean(data.getFirst("isSIP"))); + } else { + builder.setPureSip(false); + } + final String apiVersion = getApiVersion(data); + builder.setApiVersion(apiVersion); + builder.setVoiceUrl(getUrl("VoiceUrl", data)); + builder.setVoiceMethod(getMethod("VoiceMethod", data)); + builder.setVoiceFallbackUrl(getUrl("VoiceFallbackUrl", data)); + builder.setVoiceFallbackMethod(getMethod("VoiceFallbackMethod", data)); + builder.setStatusCallback(getUrl("StatusCallback", data)); + builder.setStatusCallbackMethod(getMethod("StatusCallbackMethod", data)); + builder.setHasVoiceCallerIdLookup(getHasVoiceCallerIdLookup(data)); + builder.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); + builder.setSmsUrl(getUrl("SmsUrl", data)); + builder.setSmsMethod(getMethod("SmsMethod", data)); + builder.setSmsFallbackUrl(getUrl("SmsFallbackUrl", data)); + builder.setSmsFallbackMethod(getMethod("SmsFallbackMethod", data)); + builder.setSmsApplicationSid(getSid("SmsApplicationSid", data)); + + builder.setUssdUrl(getUrl("UssdUrl", data)); + builder.setUssdMethod(getMethod("UssdMethod", data)); + builder.setUssdFallbackUrl(getUrl("UssdFallbackUrl", data)); + builder.setUssdFallbackMethod(getMethod("UssdFallbackMethod",data)); + builder.setUssdApplicationSid(getSid("UssdApplicationSid",data)); + + builder.setReferUrl(getUrl("ReferUrl", data)); + builder.setReferMethod(getMethod("ReferMethod", data)); + builder.setReferApplicationSid(getSid("ReferApplicationSid",data)); + builder.setOrganizationSid(organizationSid); + + final Configuration configuration = this.configuration.subset("runtime-settings"); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(apiVersion).append("/Accounts/").append(accountSid.toString()) + .append("/IncomingPhoneNumbers/").append(sid.toString()); + builder.setUri(URI.create(buffer.toString())); + return builder.build(); + } + + private String e164(String number) throws NumberParseException { + final PhoneNumberUtil numbersUtil = PhoneNumberUtil.getInstance(); + if(!number.startsWith("+")) { + number = "+" + number; + } + final PhoneNumber result = numbersUtil.parse(number, "US"); + if (numbersUtil.isValidNumber(result)) { + return numbersUtil.format(result, PhoneNumberFormat.E164); + } else { + throw new NumberParseException(ErrorType.NOT_A_NUMBER, "This is not a valid number"); + } + } + + private String getFriendlyName(final String phoneNumber, final MultivaluedMap data) { + String friendlyName = phoneNumber; + if (data.containsKey("FriendlyName")) { + friendlyName = data.getFirst("FriendlyName"); + } + return friendlyName; + } + + protected Response getIncomingPhoneNumber(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:IncomingPhoneNumbers"); + try{ + final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); + if (incomingPhoneNumber == null) { + return status(NOT_FOUND).build(); + } else { + // if the account that the resource belongs to does not existb while the resource does, we're having BAD parameters + if (operatedAccount == null) { + return status(BAD_REQUEST).build(); + } + secure(operatedAccount, incomingPhoneNumber.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + }catch(Exception e){ + logger.error("Exception while performing getIncomingPhoneNumber: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + protected Response getAvailableCountries(final String accountSid, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:IncomingPhoneNumbers"); + List countries = phoneNumberProvisioningManager.getAvailableCountries(); + if (countries == null) { + countries = new ArrayList(); + countries.add("US"); + } + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(countries), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new AvailableCountriesList(countries)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + + protected Response getIncomingPhoneNumbers(final String accountSid, final PhoneNumberType phoneNumberType, UriInfo info, + final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:IncomingPhoneNumbers"); + try{ + String phoneNumberFilter = info.getQueryParameters().getFirst("PhoneNumber"); + String friendlyNameFilter = info.getQueryParameters().getFirst("FriendlyName"); + String page = info.getQueryParameters().getFirst("Page"); + String reverse = info.getQueryParameters().getFirst("Reverse"); + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String sortBy = info.getQueryParameters().getFirst("SortBy"); + + pageSize = (pageSize == null) ? "50" : pageSize; + page = (page == null) ? "0" : page; + reverse = (reverse != null && "true".equalsIgnoreCase(reverse)) ? "DESC" : "ASC"; + sortBy = (sortBy != null) ? sortBy : "phone_number"; + + int limit = Integer.parseInt(pageSize); + int pageAsInt = Integer.parseInt(page); + int offset = (page == "0") ? 0 : (((pageAsInt - 1) * limit) + limit); + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byAccountSid(accountSid); + filterBuilder.byFriendlyName(friendlyNameFilter); + filterBuilder.byPhoneNumber(phoneNumberFilter); + filterBuilder.usingMode(SearchFilterMode.WILDCARD_MATCH); + final int total = dao.getTotalIncomingPhoneNumbers(filterBuilder.build()); + + if (pageAsInt > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + filterBuilder.byAccountSid(accountSid); + filterBuilder.byFriendlyName(friendlyNameFilter); + filterBuilder.byPhoneNumber(phoneNumberFilter); + filterBuilder.sortedBy(sortBy, reverse); + filterBuilder.limited(limit, offset); + filterBuilder.usingMode(SearchFilterMode.WILDCARD_MATCH); + + final List incomingPhoneNumbers = dao.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + + listConverter.setCount(total); + listConverter.setPage(pageAsInt); + listConverter.setPageSize(limit); + listConverter.setPathUri("/" + getApiVersion(null) + "/" + info.getPath()); + + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new IncomingPhoneNumberList(incomingPhoneNumbers)), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new IncomingPhoneNumberList(incomingPhoneNumbers)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + }catch(Exception e){ + logger.error("Exception while performing getIncomingPhoneNumbers: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + protected Response putIncomingPhoneNumber(final String accountSid, final MultivaluedMap data, + PhoneNumberType phoneNumberType, final MediaType responseType) { + Account account = accountsDao.getAccount(accountSid); + secure(account, "RestComm:Create:IncomingPhoneNumbers"); + try { + validate(data); + } catch (final NullPointerException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + try{ + String number = data.getFirst("PhoneNumber"); + String isSIP = data.getFirst("isSIP"); + // cater to SIP numbers + if(isSIP == null) { + try { + number = e164(number); + } catch (NumberParseException e) {} + } + Boolean isSip = Boolean.parseBoolean(isSIP); + Boolean available = true; + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byPhoneNumber(number); + List incomingPhoneNumbers = dao.getIncomingPhoneNumbersByFilter(filterBuilder.build()); + /* check if number is occupied by same organization or different. + * if it is occupied by different organization then we can add it in current. + * but it has to be pure sip as provider numbers must be unique even across organizations. + * https://github.com/RestComm/Restcomm-Connect/issues/2073 + */ + if(incomingPhoneNumbers != null && !incomingPhoneNumbers.isEmpty()){ + if(!isSip){ + //provider numbers must be unique even across organizations. + available = false; + }else{ + for(IncomingPhoneNumber incomingPhoneNumber : incomingPhoneNumbers){ + if(incomingPhoneNumber.getOrganizationSid().equals(account.getOrganizationSid())){ + available = false; + } + } + } + } + if (available) { + IncomingPhoneNumber incomingPhoneNumber = createFrom(new Sid(accountSid), data, account.getOrganizationSid()); + String domainName = organizationsDao.getOrganization(account.getOrganizationSid()).getDomainName(); + phoneNumberParameters.setVoiceUrl((callbackPort == null || callbackPort.trim().isEmpty()) ? domainName : domainName+":"+callbackPort); + phoneNumberParameters.setPhoneNumberType(phoneNumberType); + + org.restcomm.connect.provisioning.number.api.PhoneNumber phoneNumber = convertIncomingPhoneNumbertoPhoneNumber(incomingPhoneNumber); + boolean hasSuceeded = false; + boolean allowed = true; + if(phoneNumberProvisioningManager != null && isSIP == null) { + ApiRequest apiRequest = new ApiRequest(accountSid, data, ApiRequest.Type.INCOMINGPHONENUMBER); + //Before proceed to buy the DID, check with the extensions if the purchase is allowed or not + if (executePreApiAction(apiRequest)) { + if(logger.isDebugEnabled()) + logger.debug("buyNumber " + phoneNumber +" phoneNumberParameters: " + phoneNumberParameters); + hasSuceeded = phoneNumberProvisioningManager.buyNumber(phoneNumber, phoneNumberParameters); + } else { + //Extensions didn't allowed this API action + allowed = false; + if (logger.isInfoEnabled()) { + logger.info("DID purchase is now allowed for this account"); + } + } + executePostApiAction(apiRequest); + //If Extension blocked the request, return the proper error response + if (!allowed) { + String msg = "DID purchase is now allowed for this account"; + String error = "DID_QUOTA_EXCEEDED"; + return status(FORBIDDEN).entity(buildErrorResponseBody(msg, error, responseType)).build(); + } + } else if (isSIP != null) { + hasSuceeded = true; + } + if(hasSuceeded) { + if(phoneNumber.getFriendlyName() != null) { + incomingPhoneNumber.setFriendlyName(phoneNumber.getFriendlyName()); + } + if(phoneNumber.getPhoneNumber() != null) { + incomingPhoneNumber.setPhoneNumber(phoneNumber.getPhoneNumber()); + } + dao.addIncomingPhoneNumber(incomingPhoneNumber); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } + } + } + return status(BAD_REQUEST).entity("21452").build(); + }catch(Exception e){ + logger.error("Exception while performing putIncomingPhoneNumber: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + public Response updateIncomingPhoneNumber(final String accountSid, final String sid, + final MultivaluedMap data, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Modify:IncomingPhoneNumbers"); + try{ + final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); + if (incomingPhoneNumber == null) { + return status(NOT_FOUND).build(); + } + secure(operatedAccount, incomingPhoneNumber.getAccountSid(), SecuredType.SECURED_STANDARD ); + boolean updated = true; + updated = updateNumberAtPhoneNumberProvisioningManager(incomingPhoneNumber, organizationsDao.getOrganization(operatedAccount.getOrganizationSid())); + if(updated) { + dao.updateIncomingPhoneNumber(update(incomingPhoneNumber, data)); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(incomingPhoneNumber), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(incomingPhoneNumber); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + return status(BAD_REQUEST).entity("21452").build(); + }catch(Exception e){ + logger.error("Exception while performing updateIncomingPhoneNumber: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + private void validate(final MultivaluedMap data) throws RuntimeException { + if (!data.containsKey("PhoneNumber") && !data.containsKey("AreaCode")) { + throw new NullPointerException("Phone number can not be null."); + } + } + + private IncomingPhoneNumber update(final IncomingPhoneNumber incomingPhoneNumber, final MultivaluedMap data) { + if (data.containsKey("ApiVersion")) { + incomingPhoneNumber.setApiVersion(getApiVersion(data)); + } + if (data.containsKey("FriendlyName")) { + incomingPhoneNumber.setFriendlyName(data.getFirst("FriendlyName")); + } + if (data.containsKey("VoiceUrl")) { + // for all values that qualify as 'empty' populate property with null + URI uri = getUrl("VoiceUrl", data); + incomingPhoneNumber.setVoiceUrl(isEmpty(uri.toString()) ? null : uri); + } + if (data.containsKey("VoiceMethod")) { + incomingPhoneNumber.setVoiceMethod(getMethod("VoiceMethod", data)); + } + if (data.containsKey("VoiceFallbackUrl")) { + URI uri = getUrl("VoiceFallbackUrl", data); + incomingPhoneNumber.setVoiceFallbackUrl( isEmpty(uri.toString()) ? null : uri ); + } + if (data.containsKey("VoiceFallbackMethod")) { + incomingPhoneNumber.setVoiceFallbackMethod( getMethod("VoiceFallbackMethod", data) ); + } + if (data.containsKey("StatusCallback")) { + URI uri = getUrl("StatusCallback", data); + incomingPhoneNumber.setStatusCallback( isEmpty(uri.toString()) ? null : uri ); + } + if (data.containsKey("StatusCallbackMethod")) { + incomingPhoneNumber.setStatusCallbackMethod(getMethod("StatusCallbackMethod", data)); + } + if (data.containsKey("VoiceCallerIdLookup")) { + incomingPhoneNumber.setHasVoiceCallerIdLookup(getHasVoiceCallerIdLookup(data)); + } + if (data.containsKey("VoiceApplicationSid")) { + if ( org.apache.commons.lang.StringUtils.isEmpty( data.getFirst("VoiceApplicationSid") ) ) + incomingPhoneNumber.setVoiceApplicationSid(null); + else + incomingPhoneNumber.setVoiceApplicationSid(getSid("VoiceApplicationSid", data)); + } + if (data.containsKey("SmsUrl")) { + URI uri = getUrl("SmsUrl", data); + incomingPhoneNumber.setSmsUrl( isEmpty(uri.toString()) ? null : uri); + } + if (data.containsKey("SmsMethod")) { + incomingPhoneNumber.setSmsMethod(getMethod("SmsMethod", data)); + } + if (data.containsKey("SmsFallbackUrl")) { + URI uri = getUrl("SmsFallbackUrl", data); + incomingPhoneNumber.setSmsFallbackUrl( isEmpty(uri.toString()) ? null : uri ); + } + if (data.containsKey("SmsFallbackMethod")) { + incomingPhoneNumber.setSmsFallbackMethod(getMethod("SmsFallbackMethod", data)); + } + if (data.containsKey("SmsApplicationSid")) { + if ( org.apache.commons.lang.StringUtils.isEmpty( data.getFirst("SmsApplicationSid") ) ) + incomingPhoneNumber.setSmsApplicationSid(null); + else + incomingPhoneNumber.setSmsApplicationSid(getSid("SmsApplicationSid", data)); + + } + + if (data.containsKey("ReferUrl")) { + URI uri = getUrl("ReferUrl", data); + incomingPhoneNumber.setReferUrl( isEmpty(uri.toString()) ? null : uri ); + } + + if (data.containsKey("ReferMethod")) { + incomingPhoneNumber.setReferMethod(getMethod("ReferMethod", data)); + } + + if (data.containsKey("ReferApplicationSid")) { + if ( org.apache.commons.lang.StringUtils.isEmpty( data.getFirst("ReferApplicationSid") ) ) + incomingPhoneNumber.setReferApplicationSid(null); + else + incomingPhoneNumber.setReferApplicationSid(getSid("ReferApplicationSid", data)); + } + + if (data.containsKey("VoiceCapable")) { + incomingPhoneNumber.setVoiceCapable(Boolean.parseBoolean(data.getFirst("VoiceCapable"))); + } + + if (data.containsKey("VoiceCapable")) { + incomingPhoneNumber.setVoiceCapable(Boolean.parseBoolean(data.getFirst("VoiceCapable"))); + } + + if (data.containsKey("SmsCapable")) { + incomingPhoneNumber.setSmsCapable(Boolean.parseBoolean(data.getFirst("SmsCapable"))); + } + + if (data.containsKey("MmsCapable")) { + incomingPhoneNumber.setMmsCapable(Boolean.parseBoolean(data.getFirst("MmsCapable"))); + } + + if (data.containsKey("FaxCapable")) { + incomingPhoneNumber.setFaxCapable(Boolean.parseBoolean(data.getFirst("FaxCapable"))); + } + + if (data.containsKey("UssdUrl")) { + URI uri = getUrl("UssdUrl", data); + incomingPhoneNumber.setUssdUrl(isEmpty(uri.toString()) ? null : uri); + } + + if (data.containsKey("UssdMethod")) { + incomingPhoneNumber.setUssdMethod(getMethod("UssdMethod", data)); + } + + if (data.containsKey("UssdFallbackUrl")) { + URI uri = getUrl("UssdFallbackUrl", data); + incomingPhoneNumber.setUssdFallbackUrl(isEmpty(uri.toString()) ? null : uri); + } + + if (data.containsKey("UssdFallbackMethod")) { + incomingPhoneNumber.setUssdFallbackMethod(getMethod("UssdFallbackMethod", data)); + } + + if (data.containsKey("UssdApplicationSid")) { + if (org.apache.commons.lang.StringUtils.isEmpty(data.getFirst("UssdApplicationSid"))) + incomingPhoneNumber.setUssdApplicationSid(null); + else + incomingPhoneNumber.setUssdApplicationSid(getSid("UssdApplicationSid", data)); + } + + incomingPhoneNumber.setDateUpdated(DateTime.now()); + return incomingPhoneNumber; + } + + public Response deleteIncomingPhoneNumber(final String accountSid, final String sid) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Delete:IncomingPhoneNumbers"); + try{ + final IncomingPhoneNumber incomingPhoneNumber = dao.getIncomingPhoneNumber(new Sid(sid)); + if (incomingPhoneNumber == null) { + return status(NOT_FOUND).build(); + } + secure(operatedAccount, incomingPhoneNumber.getAccountSid(), SecuredType.SECURED_STANDARD); + if(phoneNumberProvisioningManager != null && (incomingPhoneNumber.isPureSip() == null || !incomingPhoneNumber.isPureSip())) { + phoneNumberProvisioningManager.cancelNumber(convertIncomingPhoneNumbertoPhoneNumber(incomingPhoneNumber)); + } + dao.removeIncomingPhoneNumber(new Sid(sid)); + return noContent().build(); + }catch(Exception e){ + logger.error("Exception while performing deleteIncomingPhoneNumber: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + /* + @SuppressWarnings("unchecked") + private List getOutboundInterfaces() { + final List uris = (List) context.getAttribute(SipServlet.OUTBOUND_INTERFACES); + return uris; + } + */ + + public static org.restcomm.connect.provisioning.number.api.PhoneNumber convertIncomingPhoneNumbertoPhoneNumber(IncomingPhoneNumber incomingPhoneNumber) { + return new org.restcomm.connect.provisioning.number.api.PhoneNumber( + incomingPhoneNumber.getFriendlyName(), + incomingPhoneNumber.getPhoneNumber(), + null, + null, + null, + null, + null, + null, + null, + null, + incomingPhoneNumber.isVoiceCapable(), + incomingPhoneNumber.isSmsCapable(), + incomingPhoneNumber.isMmsCapable(), + incomingPhoneNumber.isFaxCapable(), + false); + } + + /** + * @param targetAccountSid + * @param data + * @param responseType + * @return + */ + protected Response migrateIncomingPhoneNumbers(String targetAccountSid, MultivaluedMap data, MediaType responseType) { + Account effectiveAccount = userIdentityContext.getEffectiveAccount(); + secure(effectiveAccount, "RestComm:Modify:IncomingPhoneNumbers"); + try{ + Account targetAccount = accountsDao.getAccount(targetAccountSid); + // this is to avoid if mistakenly provided super admin account as targetAccountSid + // if this check is not in place and someone mistakenly provided super admin + // then all accounts and sub account in platform will be impacted + if(targetAccount == null){ + return status(NOT_FOUND).entity("Account not found").build(); + } + if(targetAccount.getParentSid() == null){ + return status(BAD_REQUEST).entity("Super Admin account numbers can not be migrated. Please provide a valid account sid").build(); + }else{ + String organizationSidStr = data.getFirst("OrganizationSid"); + if(organizationSidStr == null){ + return status(BAD_REQUEST).entity("OrganizationSid cannot be null").build(); + } + Sid organizationSid = null; + try{ + organizationSid = new Sid(organizationSidStr); + }catch(IllegalArgumentException iae){ + return status(BAD_REQUEST).entity("OrganizationSid is not valid").build(); + } + Organization destinationOrganization = organizationsDao.getOrganization(organizationSid); + if(destinationOrganization == null){ + return status(NOT_FOUND).entity("Destination organization not found").build(); + } + migrateNumbersFromAccountTree(targetAccount, destinationOrganization); + return status(OK).build(); + } + }catch(Exception e){ + logger.error("Exception while performing migrateIncomingPhoneNumbers: ", e); + return status(INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * @param targetAccount + * @param destinationOrganization + */ + private void migrateNumbersFromAccountTree(Account targetAccount, Organization destinationOrganization) { + List subAccountsToClose = accountsDao.getSubAccountSidsRecursive(targetAccount.getSid()); + if (subAccountsToClose != null && !subAccountsToClose.isEmpty()) { + int i = subAccountsToClose.size(); // is is the count of accounts left to process + // we iterate backwards to handle child account numbers first, parent account's numbers next + while (i > 0) { + i --; + String migrateSid = subAccountsToClose.get(i); + try { + Account subAccount = accountsDao.getAccount(new Sid(migrateSid)); + migrateSingleAccountNumbers(subAccount, destinationOrganization); + } catch (Exception e) { + // if anything bad happens, log the error and continue migrating the rest of the accounts numbers. + logger.error("Failed migrating (child) account's numbers: account sid '" + migrateSid + "'"); + } + } + } + // migrate parent account numbers too + migrateSingleAccountNumbers(targetAccount, destinationOrganization); + + } + + /** + * @param account + * @param destinationOrganization + */ + private void migrateSingleAccountNumbers(Account account, Organization destinationOrganization) { + List incomingPhoneNumbers = dao.getIncomingPhoneNumbers(account.getSid()); + if(incomingPhoneNumbers != null) { + for (int i=0; i * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; -import static javax.ws.rs.core.MediaType.*; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -44,9 +45,8 @@ public IncomingPhoneNumbersJsonEndpoint() { } @GET - public Response getIncomingPhoneNumbers(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Global, APPLICATION_JSON_TYPE); + public Response getIncomingPhoneNumbers(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.Global,info, APPLICATION_JSON_TYPE); } @POST diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersXmlEndpoint.java similarity index 76% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersXmlEndpoint.java index 551d988f56..5ca96038b6 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/IncomingPhoneNumbersXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/IncomingPhoneNumbersXmlEndpoint.java @@ -17,23 +17,26 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.provisioning.number.api.PhoneNumberType; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.provisioning.number.api.PhoneNumberType; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -87,9 +90,8 @@ public Response getAvailableCountriesAsXml(@PathParam("accountSid") final String } @GET - public Response getIncomingPhoneNumbers(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Global, APPLICATION_XML_TYPE); + public Response getIncomingPhoneNumbers(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid, PhoneNumberType.Global,info, APPLICATION_XML_TYPE); } @POST @@ -130,9 +132,8 @@ public Response updateIncomingPhoneNumberAsXmlPost(@PathParam("accountSid") fina @Path("/Local") @GET - public Response getIncomingLocalPhoneNumbersAsXml(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Local, APPLICATION_XML_TYPE); + public Response getIncomingLocalPhoneNumbersAsXml(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.Local,info, APPLICATION_XML_TYPE); } @Path("/Local") @@ -144,9 +145,8 @@ public Response putIncomingLocalPhoneNumberAsXml(@PathParam("accountSid") final @Path("/Local.json") @GET - public Response getIncomingLocalPhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Local, APPLICATION_JSON_TYPE); + public Response getIncomingLocalPhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.Local,info, APPLICATION_JSON_TYPE); } @Path("/Local.json") @@ -160,9 +160,8 @@ public Response putIncomingLocalPhoneNumberAsJSon(@PathParam("accountSid") final @Path("/TollFree") @GET - public Response getIncomingTollFreePhoneNumbersAsXml(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.TollFree, APPLICATION_XML_TYPE); + public Response getIncomingTollFreePhoneNumbersAsXml(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.TollFree,info, APPLICATION_XML_TYPE); } @Path("/TollFree") @@ -174,9 +173,8 @@ public Response putIncomingTollFreePhoneNumberAsXml(@PathParam("accountSid") fin @Path("/TollFree.json") @GET - public Response getIncomingTollFreePhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.TollFree, APPLICATION_JSON_TYPE); + public Response getIncomingTollFreePhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.TollFree,info, APPLICATION_JSON_TYPE); } @Path("/TollFree.json") @@ -190,9 +188,8 @@ public Response putIncomingTollFreePhoneNumberAsJSon(@PathParam("accountSid") fi @Path("/Mobile") @GET - public Response getIncomingMobilePhoneNumbersAsXml(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Mobile, APPLICATION_XML_TYPE); + public Response getIncomingMobilePhoneNumbersAsXml(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.Mobile,info, APPLICATION_XML_TYPE); } @Path("/Mobile") @@ -204,9 +201,8 @@ public Response putIncomingMobilePhoneNumberAsXml(@PathParam("accountSid") final @Path("/Mobile.json") @GET - public Response getIncomingMobilePhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid, - @QueryParam("PhoneNumber") final String phoneNumber, @QueryParam("FriendlyName") final String friendlyName) { - return getIncomingPhoneNumbers(accountSid, phoneNumber, friendlyName, PhoneNumberType.Mobile, APPLICATION_JSON_TYPE); + public Response getIncomingMobilePhoneNumbersAsJSon(@PathParam("accountSid") final String accountSid,@Context UriInfo info) { + return getIncomingPhoneNumbers(accountSid,PhoneNumberType.Mobile,info, APPLICATION_JSON_TYPE); } @Path("/Mobile.json") @@ -215,4 +211,20 @@ public Response putIncomingMobilePhoneNumberAsJSon(@PathParam("accountSid") fina final MultivaluedMap data) { return putIncomingPhoneNumber(accountSid, data, PhoneNumberType.Mobile, APPLICATION_JSON_TYPE); } + + @Path("/migrate") + @POST + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response migrateIncomingPhoneNumbersAsXml(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return migrateIncomingPhoneNumbers(accountSid, data, APPLICATION_XML_TYPE); + } + + @Path("/migrate.json") + @POST + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response migrateIncomingPhoneNumbersAsJson(@PathParam("accountSid") final String accountSid, + final MultivaluedMap data) { + return migrateIncomingPhoneNumbers(accountSid, data, APPLICATION_JSON_TYPE); + } } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LINK.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LINK.java new file mode 100644 index 0000000000..a0d7a616f5 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LINK.java @@ -0,0 +1,38 @@ +package org.restcomm.connect.http; + +/* + * 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 + * + */ + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.ws.rs.HttpMethod; + +/** + * + * @author + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("LINK") +public @interface LINK { +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/LogoutEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LogoutEndpoint.java similarity index 76% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/LogoutEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LogoutEndpoint.java index 5530718048..039afa6f1e 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/LogoutEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/LogoutEndpoint.java @@ -1,4 +1,4 @@ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; @@ -6,8 +6,6 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; -import org.apache.shiro.SecurityUtils; - /** * @author gvagenas */ @@ -16,7 +14,7 @@ public class LogoutEndpoint extends AbstractEndpoint { @GET public Response logout(@Context HttpServletRequest request) { - SecurityUtils.getSubject().logout(); + //SecurityUtils.getSubject().logout(); return Response.ok().build(); } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsEndpoint.java new file mode 100644 index 0000000000..1d40277a81 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsEndpoint.java @@ -0,0 +1,215 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import java.text.ParseException; +import java.util.ArrayList; + +import java.util.List; + +import static javax.ws.rs.core.MediaType.*; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.Response.*; +import static javax.ws.rs.core.Response.Status.*; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.http.converter.NotificationConverter; +import org.restcomm.connect.http.converter.NotificationListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.dao.entities.NotificationList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.NotificationFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@NotThreadSafe +public abstract class NotificationsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected NotificationsDao dao; + protected Gson gson; + protected XStream xstream; + protected NotificationListConverter listConverter; + protected String instanceId; + + public NotificationsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getNotificationsDao(); + final NotificationConverter converter = new NotificationConverter(configuration); + listConverter = new NotificationListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Notification.class, converter); + builder.registerTypeAdapter(NotificationList.class, listConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new NotificationListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + } + + protected Response getNotification(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:Notifications"); + final Notification notification = dao.getNotification(new Sid(sid)); + if (notification == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, notification.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(notification), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(notification); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } + + protected Response getNotifications(final String accountSid, UriInfo info, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Notifications"); + + boolean localInstanceOnly = true; + try { + String localOnly = info.getQueryParameters().getFirst("localOnly"); + if (localOnly != null && localOnly.equalsIgnoreCase("false")) + localInstanceOnly = false; + } catch (Exception e) { + } + + // shall we include sub-accounts cdrs in our query ? + boolean querySubAccounts = false; // be default we don't + String querySubAccountsParam = info.getQueryParameters().getFirst("SubAccounts"); + if (querySubAccountsParam != null && querySubAccountsParam.equalsIgnoreCase("true")) + querySubAccounts = true; + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + String startTime = info.getQueryParameters().getFirst("StartTime"); + String endTime = info.getQueryParameters().getFirst("EndTime"); + String error_code = info.getQueryParameters().getFirst("ErrorCode"); + String request_url = info.getQueryParameters().getFirst("RequestUrl"); + String message_text = info.getQueryParameters().getFirst("MessageText"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page.equals("0")) ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + // Shall we query cdrs of sub-accounts too ? + // if we do, we need to find the sub-accounts involved first + List ownerAccounts = null; + if (querySubAccounts) { + ownerAccounts = new ArrayList(); + ownerAccounts.add(accountSid); // we will also return parent account cdrs + ownerAccounts.addAll(accountsDao.getSubAccountSidsRecursive(new Sid(accountSid))); + } + + NotificationFilter filterForTotal; + + try { + + if (localInstanceOnly) { + filterForTotal = new NotificationFilter(accountSid, ownerAccounts, startTime, endTime, error_code, request_url, + message_text, null, null); + } else { + filterForTotal = new NotificationFilter(accountSid, ownerAccounts, startTime, endTime, error_code, request_url, + message_text, null, null, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalNotification(filterForTotal); + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + NotificationFilter filter; + + try { + if (localInstanceOnly) { + filter = new NotificationFilter(accountSid, ownerAccounts, startTime, endTime, error_code, request_url, + message_text, limit, offset); + } else { + filter = new NotificationFilter(accountSid, ownerAccounts, startTime, endTime, error_code, request_url, + message_text, limit, offset, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getNotifications(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri(info.getRequestUri().getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new NotificationList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new NotificationList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsJsonEndpoint.java similarity index 81% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsJsonEndpoint.java index 3e965a7f52..3f6aefaf95 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsJsonEndpoint.java @@ -17,15 +17,17 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -38,7 +40,7 @@ public NotificationsJsonEndpoint() { } @GET - public Response getNotifications(@PathParam("accountSid") final String accountSid) { - return getNotifications(accountSid, APPLICATION_JSON_TYPE); + public Response getNotifications(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getNotifications(accountSid, info, APPLICATION_JSON_TYPE); } } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsXmlEndpoint.java similarity index 85% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsXmlEndpoint.java index bb57dfa3bf..4b76a3e70a 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/NotificationsXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/NotificationsXmlEndpoint.java @@ -17,15 +17,17 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -50,7 +52,7 @@ public Response getNotificationAsXml(@PathParam("accountSid") final String accou } @GET - public Response getNotifications(@PathParam("accountSid") final String accountSid) { - return getNotifications(accountSid, APPLICATION_XML_TYPE); + public Response getNotifications(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getNotifications(accountSid, info, APPLICATION_XML_TYPE); } } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsEndpoint.java new file mode 100644 index 0000000000..2e54a2f252 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsEndpoint.java @@ -0,0 +1,280 @@ +/* + * 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; + +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.ok; +import static javax.ws.rs.core.Response.status; +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.FORBIDDEN; +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; + +import java.util.List; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.OrganizationList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.dns.DnsProvisioningManager; +import org.restcomm.connect.dns.DnsProvisioningManagerProvider; +import org.restcomm.connect.http.converter.OrganizationConverter; +import org.restcomm.connect.http.converter.OrganizationListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sun.jersey.core.header.LinkHeader; +import com.thoughtworks.xstream.XStream; +import java.net.URI; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.entities.ProfileAssociation; +import static org.restcomm.connect.http.ProfileEndpoint.PROFILE_REL_TYPE; +import static org.restcomm.connect.http.ProfileEndpoint.TITLE_PARAM; + +/** + * @author maria.farooq@telestax.com (Maria Farooq) + */ +public class OrganizationsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected DnsProvisioningManager dnsProvisioningManager; + protected Gson gson; + protected XStream xstream; + protected final String MSG_EMPTY_DOMAIN_NAME = "domain name can not be empty. Please, choose a valid name and try again."; + protected final String MSG_INVALID_DOMAIN_NAME_PATTERN= "Total Length of domain_name can be upto 255 Characters. It can contain only letters, number and hyphen - sign.. Please, choose a valid name and try again."; + protected final String MSG_DOMAIN_NAME_NOT_AVAILABLE = "This domain name is not available. Please, choose a different name and try again."; + protected String SUB_DOMAIN_NAME_VALIDATION_PATTERN="[A-Za-z0-9\\-]{1,255}"; + protected Pattern pattern; + private ProfileAssociationsDao profileAssociationsDao; + + protected OrganizationListConverter listConverter; + + public OrganizationsEndpoint() { + super(); + } + + // used for testing + public OrganizationsEndpoint(ServletContext context, HttpServletRequest request) { + super(context, request); + } + + @PostConstruct + void init() { + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + super.init(configuration.subset("runtime-settings")); + + registerConverters(); + + profileAssociationsDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getProfileAssociationsDao(); + + + // Make sure there is an authenticated account present when this endpoint is used + // get manager from context or create it if it does not exist + try { + dnsProvisioningManager = new DnsProvisioningManagerProvider(configuration.subset("runtime-settings"), context).get(); + } catch(Exception e) { + logger.error("Unable to get dnsProvisioningManager", e); + } + pattern = Pattern.compile(SUB_DOMAIN_NAME_VALIDATION_PATTERN); + } + + private void registerConverters(){ + final OrganizationConverter converter = new OrganizationConverter(configuration); + listConverter = new OrganizationListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.serializeNulls(); + builder.registerTypeAdapter(Organization.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(listConverter); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + public LinkHeader composeLink(Sid targetSid, UriInfo info) { + String sid = targetSid.toString(); + URI uri = info.getBaseUriBuilder().path(ProfileJsonEndpoint.class).path(sid).build(); + LinkHeader.LinkHeaderBuilder link = LinkHeader.uri(uri).parameter(TITLE_PARAM, "Profiles"); + return link.rel(PROFILE_REL_TYPE).build(); + } + + /** + * @param organizationSid + * @param responseType + * @return + */ + protected Response getOrganization(final String organizationSid, final MediaType responseType, + UriInfo info) { + //First check if the account has the required permissions in general, this way we can fail fast and avoid expensive DAO operations + checkPermission("RestComm:Read:Organizations"); + Organization organization = null; + + if (!Sid.pattern.matcher(organizationSid).matches()) { + return status(BAD_REQUEST).build(); + } else { + try { + //if account is not super admin then allow to read only affiliated organization + if (!isSuperAdmin()) { + if (userIdentityContext.getEffectiveAccount().getOrganizationSid().equals(new Sid(organizationSid))) { + organization = organizationsDao.getOrganization(new Sid(organizationSid)); + } else { + return status(FORBIDDEN).build(); + } + } else { + organization = organizationsDao.getOrganization(new Sid(organizationSid)); + } + } catch (Exception e) { + return status(NOT_FOUND).build(); + } + } + + if (organization == null) { + return status(NOT_FOUND).build(); + } else { + Response.ResponseBuilder ok = Response.ok(); + ProfileAssociation profileAssociationByTargetSid = profileAssociationsDao.getProfileAssociationByTargetSid(organizationSid); + if (profileAssociationByTargetSid != null) { + LinkHeader profileLink = composeLink(profileAssociationByTargetSid.getProfileSid(), info); + ok.header(ProfileEndpoint.LINK_HEADER, profileLink.toString()); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(organization); + return ok.type(APPLICATION_XML).entity(xstream.toXML(response)).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok.type(APPLICATION_JSON).entity(gson.toJson(organization)).build(); + } else { + return null; + } + } + } + + /** + * @param info + * @param responseType + * @return + */ + protected Response getOrganizations(UriInfo info, final MediaType responseType) { + List organizations = null; + + String status = info.getQueryParameters().getFirst("Status"); + + if(status != null && Organization.Status.getValueOf(status.toLowerCase()) != null){ + organizations = organizationsDao.getOrganizationsByStatus(Organization.Status.getValueOf(status.toLowerCase())); + }else{ + organizations = organizationsDao.getAllOrganizations(); + } + if (organizations == null || organizations.isEmpty()) { + return status(NOT_FOUND).build(); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new OrganizationList(organizations)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(organizations), APPLICATION_JSON).build(); + } else { + return null; + } + } + + /** + * putOrganization create new organization + * @param domainName + * @param data + * @param applicationJsonType + * @return + */ + protected Response putOrganization(String domainName, final UriInfo info, + MediaType responseType) { + if(domainName == null){ + return status(BAD_REQUEST).entity(MSG_EMPTY_DOMAIN_NAME ).build(); + }else{ + + //Character verification + if(!pattern.matcher(domainName).matches()){ + return status(BAD_REQUEST).entity(MSG_INVALID_DOMAIN_NAME_PATTERN).build(); + } + Organization organization; + if(dnsProvisioningManager == null) { + //Check if domain_name does not already taken inside restcomm by an organization. + organization = organizationsDao.getOrganizationByDomainName(domainName); + if(organization != null){ + return status(CONFLICT) + .entity(MSG_DOMAIN_NAME_NOT_AVAILABLE) + .build(); + } + logger.warn("No DNS provisioning Manager is configured, restcomm will not make any queries to DNS server."); + organization = new Organization(Sid.generate(Sid.Type.ORGANIZATION), domainName, DateTime.now(), DateTime.now(), Organization.Status.ACTIVE); + organizationsDao.addOrganization(organization); + }else { + //for example hosted zone id of domain restcomm.com or others. if not provided then default will be used as per configuration + String hostedZoneId = info.getQueryParameters().getFirst("HostedZoneId"); + //Check if domain_name does not already taken inside restcomm by an organization. + String completeDomainName = dnsProvisioningManager.getCompleteDomainName(domainName, hostedZoneId); + organization = organizationsDao.getOrganizationByDomainName(completeDomainName); + if(organization != null){ + return status(CONFLICT) + .entity(MSG_DOMAIN_NAME_NOT_AVAILABLE) + .build(); + } + //check if domain name already exists on dns side or not + if(dnsProvisioningManager.doesResourceRecordAlreadyExists(domainName, hostedZoneId)){ + return status(CONFLICT) + .entity(MSG_DOMAIN_NAME_NOT_AVAILABLE) + .build(); + } + if(!dnsProvisioningManager.createResourceRecord(domainName, hostedZoneId)){ + logger.error("could not create resource record on dns server"); + return status(INTERNAL_SERVER_ERROR).build(); + }else{ + organization = new Organization(Sid.generate(Sid.Type.ORGANIZATION), completeDomainName, DateTime.now(), DateTime.now(), Organization.Status.ACTIVE); + organizationsDao.addOrganization(organization); + } + } + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(organization); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(organization), APPLICATION_JSON).build(); + } else { + return null; + } + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsJsonEndpoint.java new file mode 100644 index 0000000000..aab9e9aeaf --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsJsonEndpoint.java @@ -0,0 +1,65 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author maria farooq + */ +@Path("/Organizations.json") +@ThreadSafe +public final class OrganizationsJsonEndpoint extends OrganizationsEndpoint { + public OrganizationsJsonEndpoint() { + super(); + } + + @Path("/{organizationSid}") + @GET + public Response getOrganizationAsJson(@PathParam("organizationSid") final String organizationSid, + @Context UriInfo info) { + return getOrganization(organizationSid, APPLICATION_JSON_TYPE, info); + } + + @GET + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response getOrganizations(@Context UriInfo info) { + return getOrganizations(info, APPLICATION_JSON_TYPE); + } + + @Path("/{domainName}") + @PUT + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response putOrganizationPut(@PathParam("domainName") final String domainName, @Context UriInfo info) { + return putOrganization(domainName, info, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsXmlEndpoint.java new file mode 100644 index 0000000000..4982eb04d3 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OrganizationsXmlEndpoint.java @@ -0,0 +1,66 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author maria farooq + */ +@Path("/Organizations") +@ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) +public final class OrganizationsXmlEndpoint extends OrganizationsEndpoint { + public OrganizationsXmlEndpoint() { + super(); + } + + @Path("/{organizationSid}") + @GET + public Response getOrganizationAsXml(@PathParam("organizationSid") final String organizationSid, + @Context UriInfo info) { + return getOrganization(organizationSid, APPLICATION_XML_TYPE, info); + } + + @GET + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response getOrganizations(@Context UriInfo info) { + return getOrganizations(info, APPLICATION_XML_TYPE); + } + + @Path("/{domainName}") + @PUT + @RolesAllowed(SUPER_ADMIN_ROLE) + public Response putOrganizationPut(@PathParam("domainName") final String domainName, @Context UriInfo info) { + return putOrganization(domainName, info, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyEndpoint.java similarity index 77% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyEndpoint.java index 18f048ebe6..3fb12dbbc7 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyEndpoint.java @@ -18,7 +18,7 @@ * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static akka.pattern.Patterns.ask; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; @@ -28,7 +28,6 @@ import static javax.ws.rs.core.Response.ok; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -40,15 +39,12 @@ import javax.ws.rs.core.Response; import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.telephony.GetActiveProxy; -import org.mobicents.servlet.restcomm.telephony.GetProxies; -import org.mobicents.servlet.restcomm.telephony.SwitchProxy; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.telephony.api.GetActiveProxy; +import org.restcomm.connect.telephony.api.GetProxies; +import org.restcomm.connect.telephony.api.SwitchProxy; import scala.concurrent.Await; import scala.concurrent.Future; @@ -64,17 +60,15 @@ * @author gvagenas * */ -public class OutboundProxyEndpoint extends AbstractEndpoint { +public class OutboundProxyEndpoint extends SecuredEndpoint { @Context protected ServletContext context; protected Configuration configuration; private ActorRef callManager; - private DaoManager daos; private Gson gson; private GsonBuilder builder; private XStream xstream; - protected AccountsDao accountsDao; public OutboundProxyEndpoint() { super(); @@ -84,9 +78,7 @@ public OutboundProxyEndpoint() { public void init() { configuration = (Configuration) context.getAttribute(Configuration.class.getName()); configuration = configuration.subset("runtime-settings"); - callManager = (ActorRef) context.getAttribute("org.mobicents.servlet.restcomm.telephony.CallManager"); - daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); - accountsDao = daos.getAccountsDao(); + callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager"); super.init(configuration); builder = new GsonBuilder(); builder.setPrettyPrinting(); @@ -97,11 +89,6 @@ public void init() { } protected Response getProxies(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:OutboundProxies"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } Map proxies; @@ -124,11 +111,6 @@ protected Response getProxies(final String accountSid, final MediaType responseT } protected Response switchProxy(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:OutboundProxies"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } Map proxyAfterSwitch; @@ -151,11 +133,6 @@ protected Response switchProxy(final String accountSid, final MediaType response } protected Response getActiveProxy(final String accountSid, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Read:OutboundProxies"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } Map activeProxy; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyJsonEndpoint.java similarity index 86% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyJsonEndpoint.java index 9fb08468a8..36ec9961fc 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyJsonEndpoint.java @@ -18,16 +18,18 @@ * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author gvagenas @@ -35,6 +37,7 @@ */ @Path("/Accounts/{accountSid}/OutboundProxy.json") @ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) public class OutboundProxyJsonEndpoint extends OutboundProxyEndpoint { public OutboundProxyJsonEndpoint() { super(); diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyXmlEndpoint.java similarity index 86% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyXmlEndpoint.java index 36c12ea554..4a4930abf1 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutboundProxyXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutboundProxyXmlEndpoint.java @@ -18,16 +18,18 @@ * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.*; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author gvagenas @@ -35,6 +37,7 @@ */ @Path("/Accounts/{accountSid}/OutboundProxy") @ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) public class OutboundProxyXmlEndpoint extends OutboundProxyEndpoint { public OutboundProxyXmlEndpoint() { super(); diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsEndpoint.java similarity index 76% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsEndpoint.java index d0f598150b..539b334ab4 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -26,51 +26,49 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.thoughtworks.xstream.XStream; - -import java.net.URI; -import java.util.List; +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.OutgoingCallerIdsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.OutgoingCallerId; +import org.restcomm.connect.dao.entities.OutgoingCallerIdList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.OutgoingCallerIdConverter; +import org.restcomm.connect.http.converter.OutgoingCallerIdListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; import javax.annotation.PostConstruct; import javax.servlet.ServletContext; -import javax.ws.rs.core.MediaType; - -import static javax.ws.rs.core.MediaType.*; - import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.List; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; - -import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.NotThreadSafe; -import org.mobicents.servlet.restcomm.dao.AccountsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.OutgoingCallerIdsDao; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerId; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerIdList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.OutgoingCallerIdConverter; -import org.mobicents.servlet.restcomm.http.converter.OutgoingCallerIdListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.util.StringUtils; +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.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ @NotThreadSafe -public abstract class OutgoingCallerIdsEndpoint extends AbstractEndpoint { +public abstract class OutgoingCallerIdsEndpoint extends SecuredEndpoint { @Context protected ServletContext context; protected Configuration configuration; protected OutgoingCallerIdsDao dao; protected Gson gson; protected XStream xstream; - protected AccountsDao accountsDao; public OutgoingCallerIdsEndpoint() { super(); @@ -83,7 +81,6 @@ public void init() { configuration = configuration.subset("runtime-settings"); super.init(configuration); dao = storage.getOutgoingCallerIdsDao(); - accountsDao = storage.getAccountsDao(); final OutgoingCallerIdConverter converter = new OutgoingCallerIdConverter(configuration); final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(OutgoingCallerId.class, converter); @@ -109,10 +106,8 @@ private OutgoingCallerId createFrom(final Sid accountSid, final MultivaluedMap outgoingCallerIds = dao.getOutgoingCallerIds(new Sid(accountSid)); if (APPLICATION_JSON_TYPE == responseType) { return ok(gson.toJson(outgoingCallerIds), APPLICATION_JSON).build(); @@ -159,11 +148,7 @@ protected Response getCallerIds(final String accountSid, final MediaType respons protected Response putOutgoingCallerId(final String accountSid, final MultivaluedMap data, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Create:OutgoingCallerIds"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + secure(accountsDao.getAccount(accountSid), "RestComm:Create:OutgoingCallerIds"); try { validate(data); } catch (final NullPointerException exception) { @@ -183,15 +168,13 @@ protected Response putOutgoingCallerId(final String accountSid, final Multivalue protected Response updateOutgoingCallerId(final String accountSid, final String sid, final MultivaluedMap data, final MediaType responseType) { - try { - secure(accountsDao.getAccount(accountSid), "RestComm:Modify:OutgoingCallerIds"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Modify:OutgoingCallerIds"); OutgoingCallerId outgoingCallerId = dao.getOutgoingCallerId(new Sid(sid)); if (outgoingCallerId == null) { return status(NOT_FOUND).build(); } else { + secure(operatedAccount, outgoingCallerId.getAccountSid(), SecuredType.SECURED_STANDARD); if (data.containsKey("FriendlyName")) { final String friendlyName = data.getFirst("FriendlyName"); outgoingCallerId = outgoingCallerId.setFriendlyName(friendlyName); diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsJsonEndpoint.java similarity index 93% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsJsonEndpoint.java index 854f3fd9f6..9bc7a5c1e4 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsJsonEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; @@ -27,7 +27,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsXmlEndpoint.java similarity index 83% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsXmlEndpoint.java index bda825e35c..af521bba00 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/OutgoingCallerIdsXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/OutgoingCallerIdsXmlEndpoint.java @@ -17,24 +17,26 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.DELETE; import javax.ws.rs.GET; + import static javax.ws.rs.core.MediaType.*; + import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import static javax.ws.rs.core.Response.*; -import static javax.ws.rs.core.Response.Status.*; -import org.apache.shiro.authz.AuthorizationException; +import static javax.ws.rs.core.Response.*; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Sid; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.OutgoingCallerId; +import org.restcomm.connect.commons.dao.Sid; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -47,11 +49,12 @@ public OutgoingCallerIdsXmlEndpoint() { } private Response deleteOutgoingCallerId(String accountSid, String sid) { - try { - secure(super.accountsDao.getAccount(accountSid), "RestComm:Delete:OutgoingCallerIds"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + Account operatedAccount = super.accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Delete:OutgoingCallerIds"); + OutgoingCallerId oci = dao.getOutgoingCallerId(new Sid(sid)); + if (oci != null) { + secure(operatedAccount,String.valueOf(oci.getAccountSid()), SecuredType.SECURED_STANDARD ); + } // TODO return a NOT_FOUND status code here if oci==null maybe ? dao.removeOutgoingCallerId(new Sid(sid)); return ok().build(); } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsEndpoint.java new file mode 100644 index 0000000000..f408ed915e --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsEndpoint.java @@ -0,0 +1,280 @@ +/* + * 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; + +import static akka.pattern.Patterns.ask; +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.ok; +import static javax.ws.rs.core.Response.status; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.apache.shiro.authz.AuthorizationException; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordList; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.CallDetailRecordListConverter; +import org.restcomm.connect.http.converter.ConferenceParticipantConverter; +import org.restcomm.connect.http.converter.RecordingConverter; +import org.restcomm.connect.http.converter.RecordingListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallResponse; +import org.restcomm.connect.telephony.api.GetCall; +import org.restcomm.connect.telephony.api.GetCallInfo; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; + +import akka.actor.ActorRef; +import akka.util.Timeout; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@NotThreadSafe +public abstract class ParticipantsEndpoint extends CallsEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected ActorRef callManager; + protected DaoManager daos; + protected Gson gson; + protected GsonBuilder builder; + protected XStream xstream; + protected CallDetailRecordListConverter listConverter; + protected AccountsDao accountsDao; + protected RecordingsDao recordingsDao; + protected String instanceId; + + public ParticipantsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager"); + daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); + accountsDao = daos.getAccountsDao(); + recordingsDao = daos.getRecordingsDao(); + super.init(configuration); + ConferenceParticipantConverter converter = new ConferenceParticipantConverter(configuration); + listConverter = new CallDetailRecordListConverter(configuration); + final RecordingConverter recordingConverter = new RecordingConverter(configuration); + builder = new GsonBuilder(); + builder.registerTypeAdapter(CallDetailRecord.class, converter); + builder.registerTypeAdapter(CallDetailRecordList.class, listConverter); + builder.registerTypeAdapter(Recording.class, recordingConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(recordingConverter); + xstream.registerConverter(new RecordingListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + } + + protected Response getCall(final String accountSid, final String sid, final MediaType responseType) { + Account account = daos.getAccountsDao().getAccount(accountSid); + try { + secure(account, "RestComm:Read:Calls"); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + final CallDetailRecord cdr = dao.getCallDetailRecord(new Sid(sid)); + if (cdr == null) { + return status(NOT_FOUND).build(); + } else { + try { + secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(cdr); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(cdr), APPLICATION_JSON).build(); + } else { + return null; + } + } + } + + protected Response getCalls(final String accountSid, final String conferenceSid, UriInfo info, MediaType responseType) { + Account account = daos.getAccountsDao().getAccount(accountSid); + try { + secure(account, "RestComm:Read:Calls"); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } catch (Exception e) { + } + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page == "0") ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + + final int total = dao.getTotalRunningCallDetailRecordsByConferenceSid(new Sid(conferenceSid)); + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + final List cdrs = dao.getRunningCallDetailRecordsByConferenceSid(new Sid(conferenceSid)); + if (logger.isDebugEnabled()) { + final List allCdrs = dao.getCallDetailRecordsByAccountSid(new Sid(accountSid)); + logger.debug("CDR with filter size: "+ cdrs.size()+", all CDR with no filter size: "+allCdrs.size()); + logger.debug("CDRs for ConferenceSid: "+conferenceSid); + for (CallDetailRecord cdr: allCdrs) { + logger.debug("CDR sid: "+cdr.getSid()+", status: "+cdr.getStatus()+", conferenceSid: "+cdr.getConferenceSid()); + } + } + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri("/"+getApiVersion(null)+"/"+info.getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new CallDetailRecordList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new CallDetailRecordList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } + + @SuppressWarnings("unchecked") + protected Response updateCall(final String sid, final String callSid, final MultivaluedMap data, final MediaType responseType) { + final Sid accountSid = new Sid(sid); + Account account = daos.getAccountsDao().getAccount(accountSid); + try { + secure(account, "RestComm:Modify:Calls"); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao(); + CallDetailRecord cdr = null; + try { + cdr = dao.getCallDetailRecord(new Sid(callSid)); + + if (cdr != null) { + try { + secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD); + } catch (final AuthorizationException exception) { + return status(UNAUTHORIZED).build(); + } + } else { + return Response.status(NOT_ACCEPTABLE).build(); + } + } catch (Exception e) { + return status(BAD_REQUEST).build(); + } + + Boolean mute = Boolean.valueOf(data.getFirst("Mute")); + // Mute/UnMute call + if (mute != null) { + String callPath = null; + final ActorRef call; + final CallInfo callInfo; + try { + callPath = cdr.getCallPath(); + Future future = (Future) ask(callManager, new GetCall(callPath), expires); + call = (ActorRef) Await.result(future, Duration.create(100000, TimeUnit.SECONDS)); + + future = (Future) ask(call, new GetCallInfo(), expires); + CallResponse response = (CallResponse) Await.result(future, + Duration.create(100000, TimeUnit.SECONDS)); + callInfo = response.get(); + } catch (Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + + if(call != null){ + try{ + muteUnmuteCall(mute, callInfo, call, cdr, dao); + } catch (Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } + } + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(cdr), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + return ok(xstream.toXML(new RestCommResponse(cdr)), APPLICATION_XML).build(); + } else { + return null; + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsJsonEndpoint.java new file mode 100644 index 0000000000..8fd0210156 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsJsonEndpoint.java @@ -0,0 +1,56 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@Path("/Accounts/{accountSid}/Conferences/{conferenceSid}/Participants.json") +@ThreadSafe +public final class ParticipantsJsonEndpoint extends ParticipantsEndpoint { + public ParticipantsJsonEndpoint() { + super(); + } + + @GET + public Response getParticipants(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @Context UriInfo info) { + return getCalls(accountSid, conferenceSid, info, APPLICATION_JSON_TYPE); + } + + @Path("/{callSid}") + @POST + public Response modifyCall(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @PathParam("callSid") final String callSid, + final MultivaluedMap data) { + return updateCall(accountSid, callSid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsXmlEndpoint.java new file mode 100644 index 0000000000..02eeae494a --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ParticipantsXmlEndpoint.java @@ -0,0 +1,70 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +@Path("/Accounts/{accountSid}/Conferences/{conferenceSid}/Participants") +@ThreadSafe +public final class ParticipantsXmlEndpoint extends ParticipantsEndpoint { + public ParticipantsXmlEndpoint() { + super(); + } + + @Path("/{callSid}.json") + @GET + public Response getParticipantAsJson(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @PathParam("callSid") final String callSid) { + return getCall(accountSid, callSid, APPLICATION_JSON_TYPE); + } + + @Path("/{callSid}") + @GET + public Response getParticipantAsXml(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @PathParam("callSid") final String callSid) { + return getCall(accountSid, callSid, APPLICATION_XML_TYPE); + } + + @GET + public Response getParticipants(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @Context UriInfo info) { + return getCalls(accountSid, conferenceSid, info, APPLICATION_XML_TYPE); + } + + @Path("/{callSid}") + @POST + public Response modifyCall(@PathParam("accountSid") final String accountSid, @PathParam("conferenceSid") final String conferenceSid, @PathParam("callSid") final String callSid, + final MultivaluedMap data) { + return updateCall(accountSid, callSid, data, APPLICATION_XML_TYPE); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileEndpoint.java new file mode 100644 index 0000000000..49e3f626bd --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileEndpoint.java @@ -0,0 +1,388 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jsonschema.main.JsonSchema; +import com.github.fge.jsonschema.main.JsonSchemaFactory; +import java.io.InputStream; +import java.net.URI; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.sun.jersey.core.header.LinkHeader; +import com.sun.jersey.core.header.LinkHeader.LinkHeaderBuilder; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; +import static javax.ws.rs.core.Response.status; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.ProfileAssociationsDao; +import org.restcomm.connect.dao.ProfilesDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.Profile; +import static org.restcomm.connect.dao.entities.Profile.DEFAULT_PROFILE_SID; +import org.restcomm.connect.dao.entities.ProfileAssociation; +import org.restcomm.connect.http.exceptionmappers.CustomReasonPhraseType; + +public class ProfileEndpoint { + + protected Logger logger = Logger.getLogger(ProfileEndpoint.class); + + public static final String PROFILE_CONTENT_TYPE = "application/instance+json"; + public static final String PROFILE_SCHEMA_CONTENT_TYPE = "application/schema+json"; + public static final String PROFILE_REL_TYPE = "related"; + public static final String SCHEMA_REL_TYPE = "schema"; + public static final String DESCRIBED_REL_TYPE = "describedby"; + public static final String LINK_HEADER = "Link"; + public static final String PROFILE_ENCODING = "UTF-8"; + public static final String TITLE_PARAM = "title"; + + public static final String ACCOUNTS_PREFIX = "AC"; + public static final String ORGANIZATIONS_PREFIX = "OR"; + + @Context + protected ServletContext context; + + private Configuration runtimeConfiguration; + private Configuration rootConfiguration; // top-level configuration element + private ProfilesDao profilesDao; + private ProfileAssociationsDao profileAssociationsDao; + private AccountsDao accountsDao; + private OrganizationsDao organizationsDao; + + private JsonNode schemaJson; + private JsonSchema profileSchema; + + public ProfileEndpoint() { + super(); + } + + @PostConstruct + void init() { + rootConfiguration = (Configuration) context.getAttribute(Configuration.class.getName()); + runtimeConfiguration = rootConfiguration.subset("runtime-settings"); + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + profileAssociationsDao = storage.getProfileAssociationsDao(); + this.accountsDao = storage.getAccountsDao(); + this.organizationsDao = storage.getOrganizationsDao(); + profilesDao = ((DaoManager) context.getAttribute(DaoManager.class.getName())).getProfilesDao(); + try { + schemaJson = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/rc-profile-schema.json"); + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + profileSchema = factory.getJsonSchema(schemaJson); + } catch (Exception e) { + logger.error("Error starting Profile endpoint.", e); + } + } + + class ProfileExt { + + Profile profile; + String uri; + + public ProfileExt(Profile profile, String uri) { + this.profile = profile; + this.uri = uri; + } + + public String getUri() { + return uri; + } + + public Date getDateCreated() { + return profile.getDateCreated(); + } + + public Date getDateUpdated() { + return profile.getDateUpdated(); + } + + public String getSid() { + return profile.getSid(); + } + + } + + public Response getProfiles(UriInfo info) { + try { + List allProfiles = profilesDao.getAllProfiles(); + List extProfiles = new ArrayList(allProfiles.size()); + for (Profile pAux : allProfiles) { + URI pURI = info.getBaseUriBuilder().path(this.getClass()).path(pAux.getSid()).build(); + extProfiles.add(new ProfileExt(pAux, pURI.toString())); + } + GenericEntity> entity = new GenericEntity>(extProfiles) { + }; + return Response.ok(entity, MediaType.APPLICATION_JSON).build(); + } catch (SQLException ex) { + logger.debug("getting profiles", ex); + return Response.serverError().entity(ex.getMessage()).build(); + } + } + + public Response unlinkProfile(String profileSidStr, HttpHeaders headers) { + checkProfileExists(profileSidStr); + List requestHeader = checkLinkHeader(headers); + LinkHeader link = LinkHeader.valueOf(requestHeader.get(0)); + checkRelType(link); + String targetSid = retrieveSid(link.getUri()); + checkTargetSid(new Sid(targetSid)); + profileAssociationsDao.deleteProfileAssociationByTargetSid(targetSid, profileSidStr); + return Response.ok().build(); + } + + private String retrieveSid(URI uri) { + Path paths = Paths.get(uri.getPath()); + return paths.getName(paths.getNameCount() - 1).toString(); + } + + private void checkRelType(LinkHeader link) { + if (!link.getRel().contains(PROFILE_REL_TYPE)) { + logger.debug("Only related rel type supported"); + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.BAD_REQUEST, "Only related rel type supported"); + throw new WebApplicationException(status(stat).build()); + } + } + + private List checkLinkHeader(HttpHeaders headers) { + List requestHeader = headers.getRequestHeader(LINK_HEADER); + if (requestHeader.size() != 1) { + logger.debug("Only one Link supported"); + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.BAD_REQUEST, "Only one Link supported"); + throw new WebApplicationException(status(stat).build()); + } + return requestHeader; + } + + public Response linkProfile(String profileSidStr, HttpHeaders headers, UriInfo uriInfo) { + checkProfileExists(profileSidStr); + List requestHeader = checkLinkHeader(headers); + LinkHeader link = LinkHeader.valueOf(requestHeader.get(0)); + checkRelType(link); + String targetSidStr = retrieveSid(link.getUri()); + Sid targetSid = new Sid(targetSidStr); + checkTargetSid(targetSid); + Sid profileSid = new Sid(profileSidStr); + ProfileAssociation assoc = new ProfileAssociation(profileSid, targetSid, new Date(), new Date()); + //remove previous link if any + profileAssociationsDao.deleteProfileAssociationByTargetSid(targetSidStr); + profileAssociationsDao.addProfileAssociation(assoc); + return Response.ok().build(); + } + + public Response deleteProfile(String profileSid) { + checkProfileExists(profileSid); + checkDefaultProfile(profileSid); + profilesDao.deleteProfile(profileSid); + profileAssociationsDao.deleteProfileAssociationByProfileSid(profileSid); + return Response.ok().build(); + } + + private void checkDefaultProfile(String profileSid) { + if (profileSid.equals(DEFAULT_PROFILE_SID)) { + logger.debug("Modififying default profile is forbidden"); + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.FORBIDDEN, "Modififying default profile is forbidden"); + throw new WebApplicationException(status(stat).build()); + } + } + + private Profile checkProfileExists(String profileSid) { + try { + Profile profile = profilesDao.getProfile(profileSid); + if (profile != null) { + return profile; + } else { + if (logger.isDebugEnabled()) { + logger.debug("Profile not found:" + profileSid); + } + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.NOT_FOUND, "Profile not found"); + throw new WebApplicationException(status(stat).build()); + } + } catch (SQLException ex) { + logger.debug("SQL issue getting profile.", ex); + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.INTERNAL_SERVER_ERROR, "SQL issue getting profile."); + throw new WebApplicationException(status(stat).build()); + } + } + + public Response updateProfile(String profileSid, InputStream body, UriInfo info) { + checkProfileExists(profileSid); + checkDefaultProfile(profileSid); + try { + String profileStr = IOUtils.toString(body, Charset.forName(PROFILE_ENCODING)); + final JsonNode profileJson = JsonLoader.fromString(profileStr); + ProcessingReport report = profileSchema.validate(profileJson); + if (report.isSuccess()) { + Profile profile = new Profile(profileSid, profileStr, new Date(), new Date()); + profilesDao.updateProfile(profile); + return getProfile(profileSid, info); + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(report.toString()).build(); + } + } catch (Exception ex) { + logger.debug("updating profiles", ex); + return Response.serverError().entity(ex.getMessage()).build(); + } + } + + public LinkHeader composeSchemaLink(UriInfo info) throws MalformedURLException { + URI build = info.getBaseUriBuilder().path(this.getClass()).path("/schemas/rc-profile-schema.json").build(); + return LinkHeader.uri(build).rel(DESCRIBED_REL_TYPE).build(); + } + + /** + * + * @param sid + * @return first two chars in sid + */ + private String extractSidPrefix(Sid sid) { + return sid.toString().substring(0, 2); + + } + + public LinkHeader composeLink(Sid targetSid, UriInfo info) throws MalformedURLException { + String sid = targetSid.toString(); + URI uri = null; + LinkHeaderBuilder link = null; + switch (extractSidPrefix(targetSid)) { + case ACCOUNTS_PREFIX: + uri = info.getBaseUriBuilder().path(AccountsJsonEndpoint.class).path(sid).build(); + link = LinkHeader.uri(uri).parameter(TITLE_PARAM, "Accounts"); + break; + case ORGANIZATIONS_PREFIX: + uri = info.getBaseUriBuilder().path(OrganizationsJsonEndpoint.class).path(sid).build(); + link = LinkHeader.uri(uri).parameter(TITLE_PARAM, "Organizations"); + break; + default: + } + if (link != null) { + return link.rel(PROFILE_REL_TYPE).build(); + } else { + return null; + } + } + + public void checkTargetSid(Sid sid) { + switch (extractSidPrefix(sid)) { + case ACCOUNTS_PREFIX: + Account acc = accountsDao.getAccount(sid); + if (acc == null) { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.NOT_FOUND, "Account not found"); + throw new WebApplicationException(status(stat).build()); + + } + break; + case ORGANIZATIONS_PREFIX: + Organization org = organizationsDao.getOrganization(sid); + if (org == null) { + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.NOT_FOUND, "Organization not found"); + throw new WebApplicationException(status(stat).build()); + + } + break; + default: + CustomReasonPhraseType stat = new CustomReasonPhraseType(Response.Status.NOT_FOUND, "Link not supported"); + throw new WebApplicationException(status(stat).build()); + + } + } + + public ResponseBuilder getProfileBuilder(String profileSid, UriInfo info) { + Profile profile = checkProfileExists(profileSid); + try { + Response.ResponseBuilder ok = Response.ok(profile.getProfileDocument()); + List profileAssociationsByProfileSid = profileAssociationsDao.getProfileAssociationsByProfileSid(profileSid); + for (ProfileAssociation assoc : profileAssociationsByProfileSid) { + LinkHeader composeLink = composeLink(assoc.getTargetSid(), info); + ok.header(LINK_HEADER, composeLink.toString()); + } + ok.header(LINK_HEADER, composeSchemaLink(info)); + String profileStr = profile.getProfileDocument();// IOUtils.toString(profile.getProfileDocument(), PROFILE_ENCODING); + ok.entity(profileStr); + ok.lastModified(profile.getDateUpdated()); + ok.type(PROFILE_CONTENT_TYPE); + return ok; + } catch (Exception ex) { + logger.debug("getting profile", ex); + return Response.serverError().entity(ex.getMessage()); + } + } + + public Response getProfile(String profileSid, UriInfo info) { + return getProfileBuilder(profileSid, info).build(); + } + + public Response createProfile(InputStream body, UriInfo info) { + + Response response; + try { + Sid profileSid = Sid.generate(Sid.Type.PROFILE); + String profileStr = IOUtils.toString(body, Charset.forName(PROFILE_ENCODING)); + final JsonNode profileJson = JsonLoader.fromString(profileStr); + ProcessingReport report = profileSchema.validate(profileJson); + if (report.isSuccess()) { + Profile profile = new Profile(profileSid.toString(), profileStr, new Date(), new Date()); + profilesDao.addProfile(profile); + URI location = info.getBaseUriBuilder().path(this.getClass()).path(profileSid.toString()).build(); + response = getProfileBuilder(profileSid.toString(), info).status(Status.CREATED).location(location).build(); + } else { + response = Response.status(Response.Status.BAD_REQUEST).entity(report.toString()).build(); + } + } catch (Exception ex) { + logger.debug("creating profile", ex); + return Response.serverError().entity(ex.getMessage()).build(); + } + return response; + } + + public Response getSchema(String schemaId) { + try { + JsonNode schema = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/" + schemaId); + return Response.ok(schema.toString(), PROFILE_SCHEMA_CONTENT_TYPE).build(); + } catch (IOException ex) { + logger.debug("getting schema", ex); + return Response.status(Status.NOT_FOUND).build(); + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileJsonEndpoint.java new file mode 100644 index 0000000000..b5c50b4bd4 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ProfileJsonEndpoint.java @@ -0,0 +1,124 @@ +/* + * 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; + +import com.sun.jersey.spi.resource.Singleton; +import java.io.InputStream; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +@Path("/Profiles") +@ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) +@Singleton +public class ProfileJsonEndpoint extends ProfileEndpoint { + + private static final String OVERRIDE_HDR = "X-HTTP-Method-Override"; + + @GET + @Produces(APPLICATION_JSON) + public Response getProfilesAsJson(@Context UriInfo info) { + return getProfiles(info); + } + + @POST + @Consumes(PROFILE_CONTENT_TYPE) + @Produces(PROFILE_CONTENT_TYPE) + public Response createProfileAsJson(InputStream body, @Context UriInfo info) { + return createProfile(body, info); + } + + @Path("/{profileSid}") + @GET + @Produces({PROFILE_CONTENT_TYPE, MediaType.APPLICATION_JSON}) + public Response getProfileAsJson(@PathParam("profileSid") final String profileSid, + @Context UriInfo info) { + return getProfile(profileSid, info); + } + + @Path("/{profileSid}") + @PUT + @Consumes({PROFILE_CONTENT_TYPE, MediaType.APPLICATION_JSON}) + @Produces({PROFILE_CONTENT_TYPE, MediaType.APPLICATION_JSON}) + public Response updateProfileAsJson(@PathParam("profileSid") final String profileSid, + InputStream body, @Context UriInfo info, + @Context HttpHeaders headers) { + if (headers.getRequestHeader(OVERRIDE_HDR) != null + && headers.getRequestHeader(OVERRIDE_HDR).size() > 0) { + String overrideHdr = headers.getRequestHeader(OVERRIDE_HDR).get(0); + switch (overrideHdr) { + case "LINK": + return linkProfile(profileSid, headers, info); + case "UNLINK": + return unlinkProfile(profileSid, headers); + + } + } + return updateProfile(profileSid, body, info); + } + + @Path("/{profileSid}") + @DELETE + public Response deleteProfileAsJson(@PathParam("profileSid") final String profileSid) { + return deleteProfile(profileSid); + } + + @Path("/{profileSid}") + @LINK + @Produces(APPLICATION_JSON) + public Response linkProfileAsJson(@PathParam("profileSid") final String profileSid, + @Context HttpHeaders headers, @Context UriInfo info + ) { + return linkProfile(profileSid, headers, info); + } + + @Path("/{profileSid}") + @UNLINK + @Produces(APPLICATION_JSON) + public Response unlinkProfileAsJson(@PathParam("profileSid") final String profileSid, + @Context HttpHeaders headers) { + return unlinkProfile(profileSid, headers); + } + + @Path("/schemas/{schemaId}") + @GET + @Produces(PROFILE_SCHEMA_CONTENT_TYPE) + @PermitAll + public Response getProfileSchemaAsJson(@PathParam("schemaId") final String schemaId) { + return getSchema(schemaId); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsEndpoint.java new file mode 100644 index 0000000000..31f0595cee --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsEndpoint.java @@ -0,0 +1,325 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.amazonS3.RecordingSecurityLevel; +import org.restcomm.connect.commons.amazonS3.S3AccessTool; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.RecordingFilter; +import org.restcomm.connect.dao.entities.RecordingList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.RecordingConverter; +import org.restcomm.connect.http.converter.RecordingListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.io.File; +import java.net.URI; +import java.text.ParseException; +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.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; +import static javax.ws.rs.core.Response.temporaryRedirect; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@NotThreadSafe +public abstract class RecordingsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected RecordingsDao dao; + protected Gson gson; + protected XStream xstream; + protected S3AccessTool s3AccessTool; + protected RecordingSecurityLevel securityLevel = RecordingSecurityLevel.SECURE; + protected RecordingListConverter listConverter; + protected String instanceId; + + public RecordingsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + Configuration amazonS3Configuration = configuration.subset("amazon-s3"); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getRecordingsDao(); + final RecordingConverter converter = new RecordingConverter(configuration); + listConverter = new RecordingListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Recording.class, converter); + builder.registerTypeAdapter(RecordingList.class, listConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new RecordingListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + if(!amazonS3Configuration.isEmpty()) { // Do not fail with NPE is amazonS3Configuration is not present for older install + boolean amazonS3Enabled = amazonS3Configuration.getBoolean("enabled"); + if (amazonS3Enabled) { + final String accessKey = amazonS3Configuration.getString("access-key"); + final String securityKey = amazonS3Configuration.getString("security-key"); + final String bucketName = amazonS3Configuration.getString("bucket-name"); + final String bucketFolder = amazonS3Configuration.getString("folder"); + final boolean reducedRedundancy = amazonS3Configuration.getBoolean("reduced-redundancy"); + final int minutesToRetainPublicUrl = amazonS3Configuration.getInt("minutes-to-retain-public-url", 10); + final boolean removeOriginalFile = amazonS3Configuration.getBoolean("remove-original-file"); + final String bucketRegion = amazonS3Configuration.getString("bucket-region"); + final boolean testing = amazonS3Configuration.getBoolean("testing",false); + final String testingUrl = amazonS3Configuration.getString("testing-url",null); + s3AccessTool = new S3AccessTool(accessKey, securityKey, bucketName, bucketFolder, reducedRedundancy, minutesToRetainPublicUrl, removeOriginalFile,bucketRegion, testing, testingUrl); + + securityLevel = RecordingSecurityLevel.valueOf(amazonS3Configuration.getString("security-level", "secure").toUpperCase()); + converter.setSecurityLevel(securityLevel); + } + } + + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + } + + protected Response getRecording(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:Recordings"); + final Recording recording = dao.getRecording(new Sid(sid)); + if (recording == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, recording.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(recording), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(recording); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } + + protected Response getRecordings(final String accountSid, UriInfo info, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Recordings"); + + boolean localInstanceOnly = true; + try { + String localOnly = info.getQueryParameters().getFirst("localOnly"); + if (localOnly != null && localOnly.equalsIgnoreCase("false")) + localInstanceOnly = false; + } catch (Exception e) { + } + + // shall we include sub-accounts cdrs in our query ? + boolean querySubAccounts = false; // be default we don't + String querySubAccountsParam = info.getQueryParameters().getFirst("SubAccounts"); + if (querySubAccountsParam != null && querySubAccountsParam.equalsIgnoreCase("true")) + querySubAccounts = true; + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + String startTime = info.getQueryParameters().getFirst("StartTime"); + String endTime = info.getQueryParameters().getFirst("EndTime"); + String callSid = info.getQueryParameters().getFirst("CallSid"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page.equals("0")) ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + // Shall we query cdrs of sub-accounts too ? + // if we do, we need to find the sub-accounts involved first + List ownerAccounts = null; + if (querySubAccounts) { + ownerAccounts = new ArrayList(); + ownerAccounts.add(accountSid); // we will also return parent account cdrs + ownerAccounts.addAll(accountsDao.getSubAccountSidsRecursive(new Sid(accountSid))); + } + + RecordingFilter filterForTotal; + + try { + + if (localInstanceOnly) { + filterForTotal = new RecordingFilter(accountSid, ownerAccounts, startTime, endTime, callSid, + null, null); + } else { + filterForTotal = new RecordingFilter(accountSid, ownerAccounts, startTime, endTime, callSid, + null, null, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalRecording(filterForTotal); + + if (Integer.parseInt(page) > (total / limit)) { + return status(BAD_REQUEST).build(); + } + + RecordingFilter filter; + + try { + if (localInstanceOnly) { + filter = new RecordingFilter(accountSid, ownerAccounts, startTime, endTime, callSid, + limit, offset); + } else { + filter = new RecordingFilter(accountSid, ownerAccounts, startTime, endTime, callSid, + limit, offset, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getRecordings(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri(info.getRequestUri().getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new RecordingList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new RecordingList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response getRecordingsByCall(final String accountSid, final String callSid, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Recordings"); + + final List recordings = dao.getRecordingsByCall(new Sid(callSid)); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(recordings), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new RecordingList(recordings)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + + protected Response getRecordingFile (String accountSid, String sid) { + Account operatedAccount = accountsDao.getAccount(accountSid); +// secure(operatedAccount, "RestComm:Read:Recordings"); + + final Recording recording = dao.getRecording(new Sid(sid)); + if (recording == null) { + if (logger.isInfoEnabled()) { + logger.info("Recording with SID: "+sid+", was not found"); + } + return status(NOT_FOUND).build(); + } else { +// secure(operatedAccount, recording.getAccountSid(), SecuredType.SECURED_STANDARD); + URI recordingUri = null; + try { + if (recording.getS3Uri() != null) { + String fileExtension = recording.getS3Uri().toString().endsWith("wav") ? ".wav" : ".mp4"; + recordingUri = s3AccessTool.getPublicUrl(recording.getSid() + fileExtension); + if (securityLevel.equals(RecordingSecurityLevel.REDIRECT)) { + return temporaryRedirect(recordingUri).build(); + } else { + String contentType = recordingUri.toURL().openConnection().getContentType(); + if (contentType == null || contentType.isEmpty()) { + if (fileExtension.equals(".wav")) { + contentType = "audio/x-wav"; + } else { + contentType = "video/mp4"; + } + } + //Fetch recording and serve it from here + return ok(recordingUri.toURL().openStream(), contentType).build(); + } + } else { +// String recFile = "/restcomm/recordings/" + recording.getSid() + ".wav"; +// recordingUri = UriUtils.resolve(new URI(recFile)); + String path = configuration.getString("recordings-path"); + if (!path.endsWith("/")) { + path += "/"; + } + String fileExtension = ".wav"; + if (recording.getFileUri() != null) { + fileExtension = recording.getFileUri().toString().endsWith("wav") ? ".wav" : ".mp4"; + } + path += sid.toString() + fileExtension; + + File recordingFile = new File(URI.create(path)); + if (recordingFile.exists()) { + //Fetch recording and serve it from here + String contentType; + if (fileExtension.equals(".wav")) { + contentType = "audio/x-wav"; + } else { + contentType = "video/mp4"; + } + return ok(recordingFile, contentType).build(); + } else { + return status(NOT_FOUND).build(); + } + } + } catch (Exception e) { + if (logger.isInfoEnabled()) { + logger.info("Problem during preparation of Recording file link, ", e); + } + } + } + return status(Response.Status.NOT_FOUND).build(); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsJsonEndpoint.java similarity index 81% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsJsonEndpoint.java index 4a401bd73e..3ab046a5bb 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/RecordingsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsJsonEndpoint.java @@ -17,15 +17,17 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -38,7 +40,7 @@ public RecordingsJsonEndpoint() { } @GET - public Response getRecordings(@PathParam("accountSid") final String accountSid) { - return getRecordings(accountSid, APPLICATION_JSON_TYPE); + public Response getRecordings(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getRecordings(accountSid, info, APPLICATION_JSON_TYPE); } } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsXmlEndpoint.java new file mode 100644 index 0000000000..e21d8c2127 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/RecordingsXmlEndpoint.java @@ -0,0 +1,72 @@ +/* + * 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; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Recordings") +@ThreadSafe +public final class RecordingsXmlEndpoint extends RecordingsEndpoint { + public RecordingsXmlEndpoint() { + super(); + } + + @Path("/{sid}.json") + @GET + public Response getRecordingAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getRecording(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}.wav") + @GET + public Response getRecordingAsWav(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getRecordingFile(accountSid, sid); + } + + @Path("/{sid}.mp4") + @GET + public Response getRecordingAsMp4(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getRecordingFile(accountSid, sid); + } + + @Path("/{sid}") + @GET + public Response getRecordingAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getRecording(accountSid, sid, APPLICATION_XML_TYPE); + } + + @GET + public Response getRecordings(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getRecordings(accountSid, info, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SecuredEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SecuredEndpoint.java new file mode 100644 index 0000000000..b3d02daf40 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SecuredEndpoint.java @@ -0,0 +1,449 @@ +/* + * 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; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.NotImplementedException; +import org.apache.log4j.Logger; +import org.apache.shiro.authz.Permission; +import org.apache.shiro.authz.SimpleRole; +import org.apache.shiro.authz.permission.WildcardPermissionResolver; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.http.exceptions.AuthorizationException; +import org.restcomm.connect.http.exceptions.InsufficientPermission; +import org.restcomm.connect.http.exceptions.OperatedAccountMissing; +import org.restcomm.connect.identity.AuthOutcome; +import org.restcomm.connect.identity.IdentityContext; +import org.restcomm.connect.identity.UserIdentityContext; +import org.restcomm.connect.identity.shiro.RestcommRoles; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import java.util.List; +import java.util.Set; + + +/** + * Security layer endpoint. It will scan the request for security related assets and populate the + * UserIdentityContext accordingly. Extend the class and use checkAuthenticatedAccount*() methods to apply security rules to + * your endpoint. + * + * How to use it: + * - use checkAuthenticatedAccount() method to check that a user (any user) is authenticated. + * - use checkAuthenticatedAccount(permission) method to check that an authenticated user has the required permission according to his roles + * - use checkAuthenticatedAccount(account,permission) method to check that besides permission a user also has ownership over an account + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ +public abstract class SecuredEndpoint extends AbstractEndpoint { + + // types of secured resources used to apply different policies to applications, numbers etc. + public enum SecuredType { + SECURED_APP, + SECURED_ACCOUNT, SECURED_STANDARD + } + + protected Logger logger = Logger.getLogger(SecuredEndpoint.class); + + protected UserIdentityContext userIdentityContext; + protected AccountsDao accountsDao; + protected OrganizationsDao organizationsDao; + protected IdentityContext identityContext; + @Context + protected ServletContext context; + @Context + HttpServletRequest request; + + //List of extensions for RestAPI + protected List extensions; + + public SecuredEndpoint() { + super(); + } + + // used for testing + public SecuredEndpoint(ServletContext context, HttpServletRequest request) { + this.context = context; + this.request = request; + } + + protected void init(final Configuration configuration) { + super.init(configuration); + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + this.accountsDao = storage.getAccountsDao(); + this.organizationsDao = storage.getOrganizationsDao(); + this.identityContext = (IdentityContext) context.getAttribute(IdentityContext.class.getName()); + this.userIdentityContext = new UserIdentityContext(request, accountsDao); + extensions = ExtensionController.getInstance().getExtensions(ExtensionType.RestApi); + if (logger.isInfoEnabled()) { + if (extensions != null) { + logger.info("RestAPI extensions: "+(extensions != null ? extensions.size() : "0")); + } + } + } + + /** + * Checks if the effective account is a super account (top level account) + * @return + */ + protected boolean isSuperAdmin() { + //SuperAdmin Account is the one the is + //1. Has no parent, this is the top account + //2. Is ACTIVE + return (userIdentityContext.getEffectiveAccount().getParentSid() == null) + && (userIdentityContext.getEffectiveAccount().getStatus().equals(Account.Status.ACTIVE)); + } + + /** + * Checks if the operated account is a direct child of effective account + * @return + */ + protected boolean isDirectChildOfAccount(final Account effectiveAccount, final Account operatedAccount) { + return operatedAccount.getParentSid().equals(effectiveAccount.getSid()); + } + + /** + * Checks if the effective account is a super account (top level account) + * + */ + protected void allowOnlySuperAdmin() { + if (!isSuperAdmin()) { + throw new InsufficientPermission(); + } + } + + /** + * Grants access by permission. If the effective account has a role that resolves + * to the specified permission (accoording to mappings of restcomm.xml) access is granted. + * Administrator is granted access regardless of permissions. + * + * @param permission - e.g. 'RestComm:Create:Accounts' + */ + protected void checkPermission(final String permission) { + //checkAuthenticatedAccount(); // ok there is a valid authenticated account + if ( checkPermission(permission, userIdentityContext.getEffectiveAccountRoles()) != AuthOutcome.OK ) + throw new InsufficientPermission(); + } + + // boolean overloaded form of checkAuthenticatedAccount(permission) + protected boolean isSecuredByPermission(final String permission) { + try { + checkPermission(permission); + return true; + } catch (AuthorizationException e) { + return false; + } + } + + /** + * Personalized type of grant. Besides checking 'permission' the effective account should have some sort of + * ownership over the operatedAccount. The exact type of ownership is defined in secureAccount() + * + * @param operatedAccount + * @param permission + * @throws AuthorizationException + */ + protected void secure(final Account operatedAccount, final String permission) throws AuthorizationException { + secure(operatedAccount, permission, SecuredType.SECURED_STANDARD); + } + + /** + * @param operatedAccount + * @param permission + * @param type + * @throws AuthorizationException + */ + protected void secure(final Account operatedAccount, final String permission, SecuredType type) throws AuthorizationException { + checkPermission(permission); // check an authenticated account allowed to do "permission" is available + checkOrganization(operatedAccount); // check if valid organization is attached with this account. + if (operatedAccount == null) { + // if operatedAccount is NULL, we'll probably return a 404. But let's handle that in a central place. + throw new OperatedAccountMissing(); + } + if (type == SecuredType.SECURED_STANDARD) { + if (secureLevelControl(operatedAccount, null) != AuthOutcome.OK ) + throw new InsufficientPermission(); + } else + if (type == SecuredType.SECURED_APP) { + if (secureLevelControlApplications(operatedAccount,null) != AuthOutcome.OK) + throw new InsufficientPermission(); + } else + if (type == SecuredType.SECURED_ACCOUNT) { + if (secureLevelControlAccounts(operatedAccount) != AuthOutcome.OK) + throw new InsufficientPermission(); + } + } + + /** + * @param account + * @throws IllegalStateException + */ + private void checkOrganization(Account account) throws IllegalStateException { + Sid organizationSid = account.getOrganizationSid(); + if(organizationSid == null){ + String errorMsg = "there is no organization assosiate with this account: "+account.getSid(); + logger.error(errorMsg); + throw new IllegalStateException(errorMsg); + } + Organization organization = organizationsDao.getOrganization(organizationSid); + if(organization == null || organization.getDomainName() == null || organization.getDomainName().trim().isEmpty()){ + String errorMsg = "Invalid or Null Organization: "+organization +" for account: "+account.getSid(); + logger.error(errorMsg); + throw new IllegalStateException(errorMsg); + } + } + + /** + * @param operatedAccount + * @param resourceAccountSid + * @param type + * @throws AuthorizationException + */ + protected void secure(final Account operatedAccount, final Sid resourceAccountSid, SecuredType type) throws AuthorizationException { + if (operatedAccount == null) { + // if operatedAccount is NULL, we'll probably return a 404. But let's handle that in a central place. + throw new OperatedAccountMissing(); + } + String resourceAccountSidString = resourceAccountSid == null ? null : resourceAccountSid.toString(); + if (type == SecuredType.SECURED_APP) { + if (secureLevelControlApplications(operatedAccount, resourceAccountSidString) != AuthOutcome.OK) + throw new InsufficientPermission(); + } else + if (type == SecuredType.SECURED_STANDARD){ + if (secureLevelControl(operatedAccount, resourceAccountSidString) != AuthOutcome.OK) + throw new InsufficientPermission(); + } else + if (type == SecuredType.SECURED_ACCOUNT) + throw new IllegalStateException("Account security is not supported when using sub-resources"); + else { + throw new NotImplementedException(); + } + } + +// protected void secure(final Account operatedAccount, final Sid resourceAccountSid, final String permission) throws AuthorizationException { +// secure(operatedAccount, resourceAccountSid, permission, SecuredType.SECURED_STANDARD); +// } +// +// protected void secure(final Account operatedAccount, final Sid resourceAccountSid, final String permission, final SecuredType type ) { +// secure(operatedAccount, resourceAccountSid, type); +// checkPermission(permission); // check an authbenticated account allowed to do "permission" is available +// } + + /** + * Checks is the effective account has the specified role. Only role values contained in the Restcomm Account + * are take into account. + * + * @param role + * @return true if the role exists in the Account. Otherwise it returns false. + */ + protected boolean hasAccountRole(final String role) { + if (userIdentityContext.getEffectiveAccount() != null) { + return userIdentityContext.getEffectiveAccountRoles().contains(role); + } + return false; + } + + /** + * Low level permission checking. roleNames are checked for neededPermissionString permission using permission + * mappings contained in restcomm.xml. The permission mappings are stored in RestcommRoles. + * + * Note: Administrator is granted access with eyes closed + + * @param neededPermissionString + * @param roleNames + * @return + */ + private AuthOutcome checkPermission(String neededPermissionString, Set roleNames) { + // if this is an administrator ask no more questions + if ( roleNames.contains(getAdministratorRole())) + return AuthOutcome.OK; + + // normalize the permission string + //neededPermissionString = "domain:" + neededPermissionString; + + WildcardPermissionResolver resolver = new WildcardPermissionResolver(); + Permission neededPermission = resolver.resolvePermission(neededPermissionString); + + // check the neededPermission against all roles of the user + RestcommRoles restcommRoles = identityContext.getRestcommRoles(); + for (String roleName: roleNames) { + SimpleRole simpleRole = restcommRoles.getRole(roleName); + if ( simpleRole == null) { + return AuthOutcome.FAILED; + } + else { + Set permissions = simpleRole.getPermissions(); + // check the permissions one by one + for (Permission permission: permissions) { + if (permission.implies(neededPermission)) { + if (logger.isDebugEnabled()) { + logger.debug("Granted access by permission " + permission.toString()); + } + return AuthOutcome.OK; + } + } + if (logger.isDebugEnabled()) { + logger.debug("Role " + roleName + " does not allow " + neededPermissionString); + } + } + } + return AuthOutcome.FAILED; + } + + /** + * Applies the following access control rule: + + * If no sub-resources are involved (resourceAccountSid is null): + * - If operatingAccount is the same or an ancestor of operatedAccount, access is granted + * If there are sub-resources involved: + * - If operatingAccount is the same or an ancestor of operatedAccount AND resource belongs to operatedAccount access is granted + + * @param operatedAccount the account specified in the URL + * @param resourceAccountSid the account SID property of the operated resource e.g. the accountSid of a DID. + * + */ + private AuthOutcome secureLevelControl(Account operatedAccount, String resourceAccountSid) { + Account operatingAccount = userIdentityContext.getEffectiveAccount(); + String operatingAccountSid = null; + if (operatingAccount != null) + operatingAccountSid = operatingAccount.getSid().toString(); + String operatedAccountSid = null; + if (operatedAccount != null) + operatedAccountSid = operatedAccount.getSid().toString(); + // in case we're dealing with resources, we first make sure that they are accessed under their owner account. + if (resourceAccountSid != null) + if (! resourceAccountSid.equals(operatedAccountSid)) + return AuthOutcome.FAILED; + // check parent/ancestor relationship between operatingAccount and operatedAccount + if ( operatingAccountSid.equals(operatedAccountSid) ) + return AuthOutcome.OK; + if ( operatedAccount.getParentSid() != null ) { + if (operatedAccount.getParentSid().toString().equals(operatingAccountSid)) + return AuthOutcome.OK; + else if (accountsDao.getAccountLineage(operatedAccount).contains(operatingAccountSid)) + return AuthOutcome.OK; + } + return AuthOutcome.FAILED; + } + + /** + * Uses the security policy applied by secureLevelControl(). See there for details. + * + * DEPRECATED security policy: + * + * Applies the following access control rules + * + * If an application Account Sid is given: + * - If operatingAccount is the same as the operated account and application resource belongs to operated account too + * acces is granted. + * If no application Account Sid is given: + * - If operatingAccount is the same as the operated account access is granted. + * + * NOTE: Parent/ancestor relationships on accounts do not grant access here. + * + * @param operatedAccount + * @param applicationAccountSid + * @return + */ + private AuthOutcome secureLevelControlApplications(Account operatedAccount, String applicationAccountSid) { + /* + // disabled strict policy that prevented access to sub-account applications + + // operatingAccount and operatedAccount are not null at this point + Account operatingAccount = userIdentityContext.getEffectiveAccount(); + String operatingAccountSid = operatingAccount.getSid().toString(); + String operatedAccountSid = operatedAccount.getSid().toString(); + if (!operatingAccountSid.equals(String.valueOf(operatedAccountSid))) { + return AuthOutcome.FAILED; + } else if (applicationAccountSid != null && !operatingAccountSid.equals(applicationAccountSid)) { + return AuthOutcome.FAILED; + } + return AuthOutcome.OK; + */ + + // use the more liberal default policy that applies to other entities for applications too + return secureLevelControl(operatedAccount, applicationAccountSid); + } + + /** Applies the following access control rules: + * + * If the operating account is an administrator: + * - If it is the same or parent/ancestor of the operated account access is granted. + * If the operating accoutn is NOT an administrator: + * - If it is the same as the operated account access is granted. + * + * @param operatedAccount + * @return + */ + private AuthOutcome secureLevelControlAccounts(Account operatedAccount) throws AccountHierarchyDepthCrossed { + // operatingAccount and operatedAccount are not null + Account operatingAccount = userIdentityContext.getEffectiveAccount(); + String operatingAccountSid = operatingAccount.getSid().toString(); + String operatedAccountSid = operatedAccount.getSid().toString(); + if (getAdministratorRole().equals(operatingAccount.getRole())) { + // administrator can also operate on themselves, direct children, grand-children + if (operatingAccountSid.equals(operatedAccountSid)) + return AuthOutcome.OK; + if (operatedAccount.getParentSid() != null ) { + if (operatedAccount.getParentSid().toString().equals(operatingAccountSid )) + return AuthOutcome.OK; + else if (accountsDao.getAccountLineage(operatedAccount).contains(operatingAccountSid)) + return AuthOutcome.OK; + } + return AuthOutcome.FAILED; + } else { // non-administrators can only operate directly on themselves + if ( operatingAccountSid.equals(operatedAccountSid) ) + return AuthOutcome.OK; + else + return AuthOutcome.FAILED; + } + } + + /** + * Returns the string literal for the administrator role. This role is granted implicitly access from checkAuthenticatedAccount() method. + * No need to explicitly apply it at each protected resource + * . + * @return the administrator role as string + */ + protected String getAdministratorRole() { + return "Administrator"; + } + + protected boolean executePreApiAction(final ApiRequest apiRequest) { + ExtensionController ec = ExtensionController.getInstance(); + return ec.executePreApiAction(apiRequest, extensions).isAllowed(); + } + + protected boolean executePostApiAction(final ApiRequest apiRequest) { + ExtensionController ec = ExtensionController.getInstance(); + return ec.executePostApiAction(apiRequest, extensions).isAllowed(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesEndpoint.java new file mode 100644 index 0000000000..37bbe91745 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesEndpoint.java @@ -0,0 +1,407 @@ +/* + * 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; + +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.util.Timeout; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +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.patterns.Observe; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessageFilter; +import org.restcomm.connect.dao.entities.SmsMessageList; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.converter.SmsMessageConverter; +import org.restcomm.connect.http.converter.SmsMessageListConverter; +import org.restcomm.connect.sms.api.CreateSmsSession; +import org.restcomm.connect.sms.api.SmsServiceResponse; +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 scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.math.BigDecimal; +import java.net.URI; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Currency; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import static akka.pattern.Patterns.ask; +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; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@NotThreadSafe +public abstract class SmsMessagesEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected ActorSystem system; + protected Configuration configuration; + protected ActorRef aggregator; + protected SmsMessagesDao dao; + protected Gson gson; + protected XStream xstream; + protected SmsMessageListConverter listConverter; + protected String instanceId; + + private boolean normalizePhoneNumbers; + + public SmsMessagesEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + dao = storage.getSmsMessagesDao(); + aggregator = (ActorRef) context.getAttribute("org.restcomm.connect.sms.SmsService"); + system = (ActorSystem) context.getAttribute(ActorSystem.class.getName()); + super.init(configuration); + final SmsMessageConverter converter = new SmsMessageConverter(configuration); + listConverter = new SmsMessageListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(SmsMessage.class, converter); + builder.registerTypeAdapter(SmsMessageList.class, listConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new SmsMessageListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + + normalizePhoneNumbers = configuration.getBoolean("normalize-numbers-for-outbound-calls"); + } + + protected Response getSmsMessage(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:SmsMessages"); + final SmsMessage smsMessage = dao.getSmsMessage(new Sid(sid)); + if (smsMessage == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, smsMessage.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(smsMessage), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(smsMessage); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } + + protected Response getSmsMessages(final String accountSid, UriInfo info, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:SmsMessages"); + + boolean localInstanceOnly = true; + try { + String localOnly = info.getQueryParameters().getFirst("localOnly"); + if (localOnly != null && localOnly.equalsIgnoreCase("false")) + localInstanceOnly = false; + } catch (Exception e) { + } + + // shall we include sub-accounts cdrs in our query ? + boolean querySubAccounts = false; // be default we don't + String querySubAccountsParam = info.getQueryParameters().getFirst("SubAccounts"); + if (querySubAccountsParam != null && querySubAccountsParam.equalsIgnoreCase("true")) + querySubAccounts = true; + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + // String afterSid = info.getQueryParameters().getFirst("AfterSid"); + String recipient = info.getQueryParameters().getFirst("To"); + String sender = info.getQueryParameters().getFirst("From"); + String startTime = info.getQueryParameters().getFirst("StartTime"); + String endTime = info.getQueryParameters().getFirst("EndTime"); + String body = info.getQueryParameters().getFirst("Body"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page.equals("0")) ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + // Shall we query cdrs of sub-accounts too ? + // if we do, we need to find the sub-accounts involved first + List ownerAccounts = null; + if (querySubAccounts) { + ownerAccounts = new ArrayList(); + ownerAccounts.add(accountSid); // we will also return parent account cdrs + ownerAccounts.addAll(accountsDao.getSubAccountSidsRecursive(new Sid(accountSid))); + } + + SmsMessageFilter filterForTotal; + + try { + + if (localInstanceOnly) { + filterForTotal = new SmsMessageFilter(accountSid, ownerAccounts, recipient, sender, startTime, endTime, + body, null, null); + } else { + filterForTotal = new SmsMessageFilter(accountSid, ownerAccounts, recipient, sender, startTime, endTime, + body, null, null, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalSmsMessage(filterForTotal); + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + SmsMessageFilter filter; + + try { + if (localInstanceOnly) { + filter = new SmsMessageFilter(accountSid, ownerAccounts, recipient, sender, startTime, endTime, + body, limit, offset); + } else { + filter = new SmsMessageFilter(accountSid, ownerAccounts, recipient, sender, startTime, endTime, + body, limit, offset, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getSmsMessages(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri(info.getRequestUri().getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new SmsMessageList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new SmsMessageList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } + + private void normalize(final MultivaluedMap data) throws IllegalArgumentException { + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + final String from = data.getFirst("From"); + data.remove("From"); + try { + data.putSingle("From", phoneNumberUtil.format(phoneNumberUtil.parse(from, "US"), PhoneNumberFormat.E164)); + } catch (final NumberParseException exception) { + throw new IllegalArgumentException(exception); + } + final String to = data.getFirst("To"); + data.remove("To"); + try { + data.putSingle("To", phoneNumberUtil.format(phoneNumberUtil.parse(to, "US"), PhoneNumberFormat.E164)); + } catch (final NumberParseException exception) { + throw new IllegalArgumentException(exception); + } + final String body = data.getFirst("Body"); + if (body.getBytes().length > 160) { + data.remove("Body"); + data.putSingle("Body", body.substring(0, 159)); + } + } + + @SuppressWarnings("unchecked") + protected Response putSmsMessage(final String accountSid, final MultivaluedMap data, + final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Create:SmsMessages"); + try { + validate(data); + if(normalizePhoneNumbers) + normalize(data); + } catch (final RuntimeException exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + final String sender = data.getFirst("From"); + final String recipient = data.getFirst("To"); + final String body = data.getFirst("Body"); + final SmsSessionRequest.Encoding encoding; + if (!data.containsKey("Encoding")) { + encoding = SmsSessionRequest.Encoding.GSM; + } else { + encoding = SmsSessionRequest.Encoding.valueOf(data.getFirst("Encoding").replace('-', '_')); + } + ConcurrentHashMap customRestOutgoingHeaderMap = new ConcurrentHashMap(); + Iterator iter = data.keySet().iterator(); + while (iter.hasNext()) { + String name = iter.next(); + if (name.startsWith("X-")){ + customRestOutgoingHeaderMap.put(name, data.getFirst(name)); + } + } + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + try { + Future future = (Future) ask(aggregator, new CreateSmsSession(sender, recipient, accountSid, true), expires); + Object object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + Class klass = object.getClass(); + if (SmsServiceResponse.class.equals(klass)) { + final SmsServiceResponse smsServiceResponse = (SmsServiceResponse) object; + if (smsServiceResponse.succeeded()) { + // Create an SMS record for the text message. + final SmsMessage record = sms(new Sid(accountSid), getApiVersion(data), sender, recipient, body, + SmsMessage.Status.SENDING, SmsMessage.Direction.OUTBOUND_API); + dao.addSmsMessage(record); + // Send the sms. + final ActorRef session = smsServiceResponse.get(); + final ActorRef observer = observer(); + session.tell(new Observe(observer), observer); + session.tell(new SmsSessionAttribute("record", record), null); + final SmsSessionRequest request = new SmsSessionRequest(sender, recipient, body, encoding, customRestOutgoingHeaderMap); + session.tell(request, null); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(record), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(record); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } else { + String msg = smsServiceResponse.cause().getMessage(); + String error = "SMS_LIMIT_EXCEEDED"; + return status(Response.Status.FORBIDDEN).entity(buildErrorResponseBody(msg, error, responseType)).build(); + } + } + return status(INTERNAL_SERVER_ERROR).build(); + } catch (final Exception exception) { + return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); + } + } + + private SmsMessage sms(final Sid accountSid, final String apiVersion, final String sender, final String recipient, + final String body, final SmsMessage.Status status, final SmsMessage.Direction direction) { + final SmsMessage.Builder builder = SmsMessage.builder(); + final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); + builder.setSid(sid); + builder.setAccountSid(accountSid); + builder.setSender(sender); + builder.setRecipient(recipient); + builder.setBody(body); + builder.setStatus(status); + builder.setDirection(direction); + builder.setPrice(new BigDecimal(0.00)); + // TODO - this needs to be added as property to Configuration somehow + builder.setPriceUnit(Currency.getInstance("USD")); + builder.setApiVersion(apiVersion); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(apiVersion).append("/Accounts/"); + buffer.append(accountSid.toString()).append("/SMS/Messages/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + return builder.build(); + } + + private void validate(final MultivaluedMap data) throws NullPointerException { + if (!data.containsKey("From")) { + throw new NullPointerException("From can not be null."); + } else if (!data.containsKey("To")) { + throw new NullPointerException("To can not be null."); + } else if (!data.containsKey("Body")) { + throw new NullPointerException("Body can not be null."); + } + } + + private ActorRef observer() { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new SmsSessionObserver(); + } + }); + return system.actorOf(props); + } + + private final class SmsSessionObserver extends RestcommUntypedActor { + public SmsSessionObserver() { + super(); + } + + @Override + public void onReceive(final Object message) throws Exception { + final Class klass = message.getClass(); + if (SmsSessionResponse.class.equals(klass)) { + final SmsSessionResponse response = (SmsSessionResponse) message; + final SmsSessionInfo info = response.info(); + SmsMessage record = (SmsMessage) info.attributes().get("record"); + dao.updateSmsMessage(record); + final UntypedActorContext context = getContext(); + final ActorRef self = self(); + context.stop(self); + } + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesJsonEndpoint.java similarity index 84% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesJsonEndpoint.java index 19dd5fee1e..fcc67d3e1c 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesJsonEndpoint.java @@ -17,17 +17,19 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -40,8 +42,8 @@ public SmsMessagesJsonEndpoint() { } @GET - public Response getSmsMessages(@PathParam("accountSid") final String accountSid) { - return getSmsMessages(accountSid, APPLICATION_JSON_TYPE); + public Response getSmsMessages(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getSmsMessages(accountSid, info, APPLICATION_JSON_TYPE); } @POST diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesXmlEndpoint.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesXmlEndpoint.java index 897ec2dd69..345cbdbb72 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/SmsMessagesXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SmsMessagesXmlEndpoint.java @@ -17,17 +17,19 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -52,8 +54,8 @@ public Response getSmsMessageAsXml(@PathParam("accountSid") final String account } @GET - public Response getSmsMessages(@PathParam("accountSid") final String accountSid) { - return getSmsMessages(accountSid, APPLICATION_XML_TYPE); + public Response getSmsMessages(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getSmsMessages(accountSid, info, APPLICATION_XML_TYPE); } @POST diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupervisorEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupervisorEndpoint.java new file mode 100644 index 0000000000..ee46fce07f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupervisorEndpoint.java @@ -0,0 +1,273 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http; + +import akka.actor.ActorRef; +import akka.util.Timeout; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.CallDetailRecordFilter; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.http.converter.CallinfoConverter; +import org.restcomm.connect.http.converter.MonitoringServiceConverter; +import org.restcomm.connect.http.converter.MonitoringServiceConverterCallDetails; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.monitoringservice.LiveCallsDetails; +import org.restcomm.connect.monitoringservice.MonitoringService; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.GetLiveCalls; +import org.restcomm.connect.telephony.api.GetStatistics; +import org.restcomm.connect.telephony.api.MonitoringServiceResponse; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.text.ParseException; +import java.util.concurrent.TimeUnit; + +import static akka.pattern.Patterns.ask; +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.ok; +import static javax.ws.rs.core.Response.status; + +/** + * @author gvagenas + * + */ +public class SupervisorEndpoint extends SecuredEndpoint{ + private static Logger logger = Logger.getLogger(SupervisorEndpoint.class); + + @Context + protected ServletContext context; + protected Configuration configuration; + private DaoManager daos; + private Gson gson; + private GsonBuilder builder; + private XStream xstream; + private ActorRef monitoringService; + + public SupervisorEndpoint() { + super(); + } + + @PostConstruct + public void init() { + monitoringService = (ActorRef) context.getAttribute(MonitoringService.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); + super.init(configuration); + CallinfoConverter converter = new CallinfoConverter(configuration); + MonitoringServiceConverter listConverter = new MonitoringServiceConverter(configuration); + MonitoringServiceConverterCallDetails callDetailsConverter = new MonitoringServiceConverterCallDetails(configuration); + builder = new GsonBuilder(); + builder.registerTypeAdapter(CallInfo.class, converter); + builder.registerTypeAdapter(MonitoringServiceResponse.class, listConverter); + builder.registerTypeAdapter(LiveCallsDetails.class, callDetailsConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(listConverter); + xstream.registerConverter(callDetailsConverter); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + protected Response pong(final String accountSid, final MediaType responseType) { + //following 2 things are enough to grant access: 1. a valid authentication token is present. 2 it is a super admin. + CallDetailRecordFilter filterForTotal; + try { + filterForTotal = new CallDetailRecordFilter("", null, null, null, null, null,null, + null, null, null, null); + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + int totalCalls = daos.getCallDetailRecordsDao().getTotalCallDetailRecords(filterForTotal); + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse("TotalCalls: "+totalCalls); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson("TotalCalls: "+totalCalls), APPLICATION_JSON).build(); + } else { + return null; + } + } + + protected Response getMetrics(final String accountSid, final UriInfo info, final MediaType responseType) { + //following 2 things are enough to grant access: 1. a valid authentication token is present. 2 it is a super admin. + boolean withLiveCallDetails = false; + boolean withMgcpStats = false; + if (info != null && info.getQueryParameters().containsKey("LiveCallDetails") ) { + withLiveCallDetails = Boolean.parseBoolean(info.getQueryParameters().getFirst("LiveCallDetails")); + } + + if (info != null && info.getQueryParameters().containsKey("MgcpStats") ) { + withMgcpStats = Boolean.parseBoolean(info.getQueryParameters().getFirst("MgcpStats")); + } + //Get the list of live calls from Monitoring Service + MonitoringServiceResponse monitoringServiceResponse; + try { + final Timeout expires = new Timeout(Duration.create(5, TimeUnit.SECONDS)); + GetStatistics getStatistics = new GetStatistics(withLiveCallDetails, withMgcpStats, accountSid); + Future future = (Future) ask(monitoringService, getStatistics, expires); + monitoringServiceResponse = (MonitoringServiceResponse) Await.result(future, Duration.create(5, TimeUnit.SECONDS)); + } catch (Exception exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + if (monitoringServiceResponse != null) { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(monitoringServiceResponse); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + Response response = ok(gson.toJson(monitoringServiceResponse), APPLICATION_JSON).build(); + if(logger.isDebugEnabled()){ + logger.debug("Supervisor endpoint response: "+gson.toJson(monitoringServiceResponse)); + } + return response; + } else { + return null; + } + } else { + return null; + } + } + + protected Response getLiveCalls(final String accountSid, final MediaType responseType) { + //following 2 things are enough to grant access: 1. a valid authentication token is present. 2 it is a super admin. + LiveCallsDetails callDetails; + try { + final Timeout expires = new Timeout(Duration.create(5, TimeUnit.SECONDS)); + GetLiveCalls getLiveCalls = new GetLiveCalls(); + Future future = (Future) ask(monitoringService, getLiveCalls, expires); + callDetails = (LiveCallsDetails) Await.result(future, Duration.create(5, TimeUnit.SECONDS)); + } catch (Exception exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + if (callDetails != null) { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(callDetails); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + Response response = ok(gson.toJson(callDetails), APPLICATION_JSON).build(); + if(logger.isDebugEnabled()){ + logger.debug("Supervisor endpoint response: "+gson.toJson(callDetails)); + } + return response; + } else { + return null; + } + } else { + return null; + } + } + + //Register a remote location where Restcomm will send monitoring updates + protected Response registerForUpdates(final String accountSid, final UriInfo info, MediaType responseType) { + //following 2 things are enough to grant access: 1. a valid authentication token is present. 2 it is a super admin. + boolean withLiveCallDetails = false; + boolean withMgcpStats = false; + if (info != null && info.getQueryParameters().containsKey("LiveCallDetails") ) { + withLiveCallDetails = Boolean.parseBoolean(info.getQueryParameters().getFirst("LiveCallDetails")); + } + + if (info != null && info.getQueryParameters().containsKey("MgcpStats") ) { + withMgcpStats = Boolean.parseBoolean(info.getQueryParameters().getFirst("MgcpStats")); + } + //Get the list of live calls from Monitoring Service + MonitoringServiceResponse monitoringServiceResponse; + try { + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + GetStatistics getStatistics = new GetStatistics(withLiveCallDetails, withMgcpStats, accountSid); + Future future = (Future) ask(monitoringService, getStatistics, expires); + monitoringServiceResponse = (MonitoringServiceResponse) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + } catch (Exception exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + if (monitoringServiceResponse != null) { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(monitoringServiceResponse); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + Response response = ok(gson.toJson(monitoringServiceResponse), APPLICATION_JSON).build(); + return response; + } else { + return null; + } + } else { + return null; + } + } + + //Register a remote location where Restcomm will send monitoring updates for a specific Call + protected Response registerForCallUpdates(final String accountSid, final String callSid, final MultivaluedMap data, MediaType responseType) { + //following 2 things are enough to grant access: 1. a valid authentication token is present. 2 it is a super admin. + final String url = data.getFirst("Url"); + final String refresh = data.getFirst("Refresh"); + boolean withLiveCallDetails = false; + boolean withMgcpStats = false; + if (data != null && data.containsKey("LiveCallDetails")) { + withLiveCallDetails = Boolean.parseBoolean(data.getFirst("LiveCallDetails")); + } + + if (data != null && data.containsKey("MgcpStats") ) { + withMgcpStats = Boolean.parseBoolean(data.getFirst("MgcpStats")); + } + //Get the list of live calls from Monitoring Service + MonitoringServiceResponse monitoringServiceResponse; + try { + final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS)); + GetStatistics getStatistics = new GetStatistics(withLiveCallDetails, withMgcpStats, accountSid); + Future future = (Future) ask(monitoringService, getStatistics, expires); + monitoringServiceResponse = (MonitoringServiceResponse) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + } catch (Exception exception) { + return status(BAD_REQUEST).entity(exception.getMessage()).build(); + } + if (monitoringServiceResponse != null) { + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(monitoringServiceResponse); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + Response response = ok(gson.toJson(monitoringServiceResponse), APPLICATION_JSON).build(); + return response; + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupservisorJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupservisorJsonEndpoint.java new file mode 100644 index 0000000000..068df9aa0a --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/SupservisorJsonEndpoint.java @@ -0,0 +1,85 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static org.restcomm.connect.http.security.AccountPrincipal.SUPER_ADMIN_ROLE; + +import javax.annotation.security.RolesAllowed; + +/** + * @author gvagenas + * + */ +@Path("/Accounts/{accountSid}/Supervisor.json") +@ThreadSafe +@RolesAllowed(SUPER_ADMIN_ROLE) +public class SupservisorJsonEndpoint extends SupervisorEndpoint{ + + public SupservisorJsonEndpoint() { + super(); + } + + //Simple PING/PONG message + @GET + public Response ping(@PathParam("accountSid") final String accountSid) { + return pong(accountSid, APPLICATION_JSON_TYPE); + } + + //Get statistics + @Path("/metrics") + @GET + public Response getMetrics(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getMetrics(accountSid, info, APPLICATION_JSON_TYPE); + } + + //Get live calls + @Path("/livecalls") + @GET + public Response getLiveCalls(@PathParam("accountSid") final String accountSid) { + return getLiveCalls(accountSid, APPLICATION_JSON_TYPE); + } + + //Register a remote location where Restcomm will send monitoring updates + @Path("/remote") + @POST + public Response registerForMetricsUpdates(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return registerForUpdates(accountSid, info, APPLICATION_JSON_TYPE); + } + + //Register a remote location where Restcomm will send monitoring updates for a specific Call + @Path("/remote/{sid}") + @POST + public Response registerForCallMetricsUpdates(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid, final MultivaluedMap data) { + return registerForCallUpdates(accountSid, sid, data, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsEndpoint.java new file mode 100644 index 0000000000..c65851d5e3 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsEndpoint.java @@ -0,0 +1,213 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import java.text.ParseException; +import java.util.ArrayList; + +import java.util.List; + +import static javax.ws.rs.core.MediaType.*; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.Response.*; +import static javax.ws.rs.core.Response.Status.*; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.NotThreadSafe; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.converter.TranscriptionConverter; +import org.restcomm.connect.http.converter.TranscriptionListConverter; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.TranscriptionsDao; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Transcription; +import org.restcomm.connect.dao.entities.TranscriptionList; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.TranscriptionFilter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@NotThreadSafe +public abstract class TranscriptionsEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected TranscriptionsDao dao; + protected Gson gson; + protected XStream xstream; + protected TranscriptionListConverter listConverter; + protected String instanceId; + + public TranscriptionsEndpoint() { + super(); + } + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getTranscriptionsDao(); + final TranscriptionConverter converter = new TranscriptionConverter(configuration); + listConverter = new TranscriptionListConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Transcription.class, converter); + builder.registerTypeAdapter(TranscriptionList.class, listConverter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new TranscriptionListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + xstream.registerConverter(listConverter); + + instanceId = RestcommConfiguration.getInstance().getMain().getInstanceId(); + } + + protected Response getTranscription(final String accountSid, final String sid, final MediaType responseType) { + Account operatedAccount = accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Read:Transcriptions"); + final Transcription transcription = dao.getTranscription(new Sid(sid)); + if (transcription == null) { + return status(NOT_FOUND).build(); + } else { + secure(operatedAccount, transcription.getAccountSid(), SecuredType.SECURED_STANDARD); + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(transcription), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(transcription); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } + + protected Response getTranscriptions(final String accountSid, UriInfo info, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Transcriptions"); + + boolean localInstanceOnly = true; + try { + String localOnly = info.getQueryParameters().getFirst("localOnly"); + if (localOnly != null && localOnly.equalsIgnoreCase("false")) + localInstanceOnly = false; + } catch (Exception e) { + } + + // shall we include sub-accounts cdrs in our query ? + boolean querySubAccounts = false; // be default we don't + String querySubAccountsParam = info.getQueryParameters().getFirst("SubAccounts"); + if (querySubAccountsParam != null && querySubAccountsParam.equalsIgnoreCase("true")) + querySubAccounts = true; + + String pageSize = info.getQueryParameters().getFirst("PageSize"); + String page = info.getQueryParameters().getFirst("Page"); + String startTime = info.getQueryParameters().getFirst("StartTime"); + String endTime = info.getQueryParameters().getFirst("EndTime"); + String transcriptionText = info.getQueryParameters().getFirst("TranscriptionText"); + + if (pageSize == null) { + pageSize = "50"; + } + + if (page == null) { + page = "0"; + } + + int limit = Integer.parseInt(pageSize); + int offset = (page.equals("0")) ? 0 : (((Integer.parseInt(page) - 1) * Integer.parseInt(pageSize)) + Integer + .parseInt(pageSize)); + + // Shall we query cdrs of sub-accounts too ? + // if we do, we need to find the sub-accounts involved first + List ownerAccounts = null; + if (querySubAccounts) { + ownerAccounts = new ArrayList(); + ownerAccounts.add(accountSid); // we will also return parent account cdrs + ownerAccounts.addAll(accountsDao.getSubAccountSidsRecursive(new Sid(accountSid))); + } + + TranscriptionFilter filterForTotal; + + try { + + if (localInstanceOnly) { + filterForTotal = new TranscriptionFilter(accountSid, ownerAccounts, startTime, endTime, + transcriptionText, null, null); + } else { + filterForTotal = new TranscriptionFilter(accountSid, ownerAccounts, startTime, endTime, + transcriptionText, null, null, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final int total = dao.getTotalTranscription(filterForTotal); + + if (Integer.parseInt(page) > (total / limit)) { + return status(javax.ws.rs.core.Response.Status.BAD_REQUEST).build(); + } + + TranscriptionFilter filter; + + try { + if (localInstanceOnly) { + filter = new TranscriptionFilter(accountSid, ownerAccounts, startTime, endTime, + transcriptionText, limit, offset); + } else { + filter = new TranscriptionFilter(accountSid, ownerAccounts, startTime, endTime, + transcriptionText, limit, offset, instanceId); + } + } catch (ParseException e) { + return status(BAD_REQUEST).build(); + } + + final List cdrs = dao.getTranscriptions(filter); + + listConverter.setCount(total); + listConverter.setPage(Integer.parseInt(page)); + listConverter.setPageSize(Integer.parseInt(pageSize)); + listConverter.setPathUri(info.getRequestUri().getPath()); + + if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new TranscriptionList(cdrs)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(new TranscriptionList(cdrs)), APPLICATION_JSON).build(); + } else { + return null; + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsJsonEndpoint.java similarity index 85% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsJsonEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsJsonEndpoint.java index 60c7c7ad9f..b124df92d4 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/TranscriptionsJsonEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsJsonEndpoint.java @@ -17,13 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import javax.ws.rs.GET; import static javax.ws.rs.core.MediaType.*; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -35,7 +37,7 @@ public TranscriptionsJsonEndpoint() { } @GET - public Response getTranscriptions(@PathParam("accountSid") final String accountSid) { - return getTranscriptions(accountSid, APPLICATION_JSON_TYPE); + public Response getTranscriptions(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getTranscriptions(accountSid, info, APPLICATION_JSON_TYPE); } } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsXmlEndpoint.java new file mode 100644 index 0000000000..3f523bcd29 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/TranscriptionsXmlEndpoint.java @@ -0,0 +1,75 @@ +/* + * 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; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import static javax.ws.rs.core.MediaType.*; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import static javax.ws.rs.core.Response.*; +import javax.ws.rs.core.UriInfo; + +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Transcription; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Path("/Accounts/{accountSid}/Transcriptions") +public final class TranscriptionsXmlEndpoint extends TranscriptionsEndpoint { + public TranscriptionsXmlEndpoint() { + super(); + } + + @Path("/{sid}") + @DELETE + public Response deleteTranscription(@PathParam("accountSid") String accountSid, @PathParam("sid") String sid) { + Account operatedAccount = super.accountsDao.getAccount(accountSid); + secure(operatedAccount, "RestComm:Delete:Transcriptions"); + Transcription transcription = dao.getTranscription(new Sid(sid)); + if (transcription != null) { + secure(operatedAccount, String.valueOf(transcription.getAccountSid()), SecuredType.SECURED_STANDARD ); + } + // TODO return NOT_FOUND if transcrtiption==null + dao.removeTranscription(new Sid(sid)); + return ok().build(); + } + + @Path("/{sid}.json") + @GET + public Response getTranscriptionAsJson(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getTranscription(accountSid, sid, APPLICATION_JSON_TYPE); + } + + @Path("/{sid}") + @GET + public Response getTranscriptionAsXml(@PathParam("accountSid") final String accountSid, @PathParam("sid") final String sid) { + return getTranscription(accountSid, sid, APPLICATION_XML_TYPE); + } + + @GET + public Response getTranscriptions(@PathParam("accountSid") final String accountSid, @Context UriInfo info) { + return getTranscriptions(accountSid, info, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UNLINK.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UNLINK.java new file mode 100644 index 0000000000..10fbb2be1f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UNLINK.java @@ -0,0 +1,38 @@ +package org.restcomm.connect.http; + +/* + * 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 + * + */ + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.ws.rs.HttpMethod; + +/** + * + * @author + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("UNLINK") +public @interface UNLINK { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageEndpoint.java new file mode 100644 index 0000000000..227a201c68 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageEndpoint.java @@ -0,0 +1,165 @@ +/* + * 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; + +import static javax.ws.rs.core.MediaType.*; +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.NOT_FOUND; +import static javax.ws.rs.core.Response.ok; +import static javax.ws.rs.core.Response.status; + +import java.util.List; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.converter.UsageListConverter; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.UsageDao; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Usage; +import org.restcomm.connect.dao.entities.UsageList; +import org.restcomm.connect.http.converter.UsageConverter; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; + +/** + * @author charles.roufay@telestax.com (Charles Roufay) + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@ThreadSafe +public abstract class UsageEndpoint extends SecuredEndpoint { + @Context + protected ServletContext context; + protected Configuration configuration; + protected UsageDao dao; + protected Gson gson; + protected XStream xstream; + + public UsageEndpoint() { + super(); + } + + public static final Pattern relativePattern = Pattern.compile("(\\+|\\-)(\\d+)day[s]"); + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getUsageDao(); + final UsageConverter converter = new UsageConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Usage.class, converter); + builder.setPrettyPrinting(); + gson = builder.disableHtmlEscaping().create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new UsageListConverter(configuration)); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + protected Response getUsage(final String accountSid, final String subresource, UriInfo info, final MediaType responseType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Usage"); + + String categoryStr = info.getQueryParameters().getFirst("Category"); + String startDateStr = info.getQueryParameters().getFirst("StartDate"); + String endDateStr = info.getQueryParameters().getFirst("EndDate"); + //pass in reqUri without query params + String reqUri = request.getServletPath() + "/" + info.getPath(false); + + Usage.Category category = categoryStr != null ? Usage.Category.valueOf(categoryStr) : null; + DateTime startDate = new DateTime(0).withTimeAtStartOfDay(); + if (startDateStr != null) { + try { + startDate = DateTimeFormat.forPattern("yyyyy-MM-dd").parseDateTime(startDateStr); + } + catch (IllegalArgumentException iae) { + // TODO: Support relative + } + } + DateTime endDate = new DateTime(); + if (endDateStr != null) { + try { + endDate = DateTimeFormat.forPattern("yyyyy-MM-dd").parseDateTime(endDateStr); + } + catch (IllegalArgumentException iae) { + // TODO: Support relative + } + } + + final List usage; + if (subresource.toLowerCase().equals("daily")) { + usage = dao.getUsageDaily(new Sid(accountSid), category, startDate, endDate, reqUri); + } + else if (subresource.toLowerCase().equals("monthly")) { + usage = dao.getUsageMonthly(new Sid(accountSid), category, startDate, endDate, reqUri); + } + else if (subresource.toLowerCase().equals("yearly")) { + usage = dao.getUsageYearly(new Sid(accountSid), category, startDate, endDate, reqUri); + } + else if (subresource.toLowerCase().equals("alltime")) { + usage = dao.getUsageAllTime(new Sid(accountSid), category, startDate, endDate, reqUri); + } else if (subresource.toLowerCase().equals("today")) { + usage = dao.getUsageAllTime(new Sid(accountSid), category, DateTime.now(), DateTime.now(), reqUri); + } + else if (subresource.toLowerCase().equals("yesterday")) { + usage = dao.getUsageAllTime(new Sid(accountSid), category, DateTime.now().minusDays(1), DateTime.now().minusDays(1), reqUri); + } + else if (subresource.toLowerCase().equals("thismonth")) { + usage = dao.getUsageAllTime(new Sid(accountSid), category, DateTime.now().dayOfMonth().withMinimumValue(), DateTime.now().dayOfMonth().withMaximumValue(), reqUri); + } + else if (subresource.toLowerCase().equals("lastmonth")) { + usage = dao.getUsageAllTime(new Sid(accountSid), category, DateTime.now().minusMonths(1).dayOfMonth().withMinimumValue(), DateTime.now().minusMonths(1).dayOfMonth().withMaximumValue(), reqUri); + } + else { + usage = dao.getUsageAllTime(new Sid(accountSid), category, startDate, endDate, reqUri); + } + + if (usage == null) { + return status(NOT_FOUND).build(); + } else { + if (APPLICATION_JSON_TYPE == responseType) { + return ok(gson.toJson(usage), APPLICATION_JSON).build(); + } else if (APPLICATION_XML_TYPE == responseType) { + final RestCommResponse response = new RestCommResponse(new UsageList(usage)); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else { + return null; + } + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageJsonEndpoint.java new file mode 100644 index 0000000000..f0fb60ef62 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageJsonEndpoint.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +public class UsageJsonEndpoint { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageXmlEndpoint.java new file mode 100644 index 0000000000..f816c2f236 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UsageXmlEndpoint.java @@ -0,0 +1,56 @@ +/* + * 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; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@Path("/Accounts/{accountSid}/Usage/Records") +@ThreadSafe +public final class UsageXmlEndpoint extends UsageEndpoint { + public UsageXmlEndpoint() { + super(); + } + + @Path("/{subresource}.json") + @GET + public Response getUsageAsJson(@PathParam("accountSid") final String accountSid, @PathParam("subresource") final String subresource, @Context UriInfo info) { + return getUsage(accountSid, subresource, info, APPLICATION_JSON_TYPE); + } + + @Path("/{subresource}") + @GET + public Response getUsageAsXml(@PathParam("accountSid") final String accountSid, @PathParam("subresource") final String subresource, @Context UriInfo info) { + return getUsage(accountSid, subresource, info, APPLICATION_XML_TYPE); + } + + } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushEndpoint.java similarity index 83% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushEndpoint.java index 234f544ac4..27918a5296 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static akka.pattern.Patterns.ask; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; @@ -28,7 +28,6 @@ import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; import java.net.URI; import java.util.concurrent.TimeUnit; @@ -41,21 +40,21 @@ import javax.ws.rs.core.Response; import org.apache.commons.configuration.Configuration; -import org.apache.shiro.authz.AuthorizationException; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordList; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.http.converter.CallDetailRecordConverter; -import org.mobicents.servlet.restcomm.http.converter.CallDetailRecordListConverter; -import org.mobicents.servlet.restcomm.http.converter.RestCommResponseConverter; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallManagerResponse; -import org.mobicents.servlet.restcomm.telephony.CallResponse; -import org.mobicents.servlet.restcomm.telephony.CreateCall; -import org.mobicents.servlet.restcomm.telephony.ExecuteCallScript; -import org.mobicents.servlet.restcomm.telephony.GetCallInfo; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordList; +import org.restcomm.connect.dao.entities.RestCommResponse; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.telephony.CreateCallType; +import org.restcomm.connect.http.converter.CallDetailRecordConverter; +import org.restcomm.connect.http.converter.CallDetailRecordListConverter; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallManagerResponse; +import org.restcomm.connect.telephony.api.CallResponse; +import org.restcomm.connect.telephony.api.CreateCall; +import org.restcomm.connect.telephony.api.ExecuteCallScript; +import org.restcomm.connect.telephony.api.GetCallInfo; import scala.concurrent.Await; import scala.concurrent.Future; @@ -71,7 +70,7 @@ * @author gvagenas * */ -public class UssdPushEndpoint extends AbstractEndpoint { +public class UssdPushEndpoint extends SecuredEndpoint { @Context protected ServletContext context; @@ -91,7 +90,7 @@ public UssdPushEndpoint() { public void init() { configuration = (Configuration) context.getAttribute(Configuration.class.getName()); configuration = configuration.subset("runtime-settings"); - ussdCallManager = (ActorRef) context.getAttribute("org.mobicents.servlet.restcomm.ussd.telephony.UssdCallManager"); + ussdCallManager = (ActorRef) context.getAttribute("org.restcomm.connect.ussd.telephony.UssdCallManager"); daos = (DaoManager) context.getAttribute(DaoManager.class.getName()); super.init(configuration); CallDetailRecordConverter converter = new CallDetailRecordConverter(configuration); @@ -111,11 +110,7 @@ public void init() { @SuppressWarnings("unchecked") protected Response putCall(final String accountSid, final MultivaluedMap data, final MediaType responseType) { final Sid accountId = new Sid(accountSid); - try { - secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Create:Calls"); - } catch (final AuthorizationException exception) { - return status(UNAUTHORIZED).build(); - } + secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Create:Calls"); try { validate(data); } catch (final RuntimeException exception) { @@ -125,12 +120,14 @@ protected Response putCall(final String accountSid, final MultivaluedMap future = (Future) ask(ussdCallManager, create, expires); Object object = Await.result(future, Duration.create(10, TimeUnit.SECONDS)); @@ -152,10 +149,8 @@ protected Response putCall(final String accountSid, final MultivaluedMap * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushXmlEndpoint.java similarity index 96% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushXmlEndpoint.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushXmlEndpoint.java index 80b9ea3f53..01e8409edc 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/UssdPushXmlEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/UssdPushXmlEndpoint.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http; +package org.restcomm.connect.http; import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionEndpoint.java new file mode 100644 index 0000000000..d1717903df --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionEndpoint.java @@ -0,0 +1,103 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.Version; +import org.restcomm.connect.commons.VersionEntity; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.http.converter.RestCommResponseConverter; +import org.restcomm.connect.http.converter.VersionConverter; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.UsageDao; +import org.restcomm.connect.dao.entities.RestCommResponse; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.MediaType.*; +import static javax.ws.rs.core.Response.ok; + +/** + * @author gvagenas + * + */ +@ThreadSafe +public class VersionEndpoint extends SecuredEndpoint { + private static Logger logger = Logger.getLogger(VersionEndpoint.class); + + @Context + protected ServletContext context; + protected Configuration configuration; + protected UsageDao dao; + protected Gson gson; + protected XStream xstream; + + @PostConstruct + public void init() { + final DaoManager storage = (DaoManager) context.getAttribute(DaoManager.class.getName()); + configuration = (Configuration) context.getAttribute(Configuration.class.getName()); + configuration = configuration.subset("runtime-settings"); + super.init(configuration); + dao = storage.getUsageDao(); + accountsDao = storage.getAccountsDao(); + final VersionConverter converter = new VersionConverter(configuration); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(VersionEntity.class, converter); + builder.setPrettyPrinting(); + gson = builder.create(); + xstream = new XStream(); + xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(converter); + xstream.registerConverter(new RestCommResponseConverter(configuration)); + } + + protected Response getVersion(final String accountSid, final MediaType mediaType) { + secure(accountsDao.getAccount(accountSid), "RestComm:Read:Usage"); + + VersionEntity versionEntity = Version.getVersionEntity(); + + if (versionEntity != null) { + if (APPLICATION_XML_TYPE == mediaType) { + final RestCommResponse response = new RestCommResponse(versionEntity); + return ok(xstream.toXML(response), APPLICATION_XML).build(); + } else if (APPLICATION_JSON_TYPE == mediaType) { + Response response = ok(gson.toJson(versionEntity), APPLICATION_JSON).build(); + if(logger.isDebugEnabled()){ + logger.debug("Supervisor endpoint response: "+gson.toJson(versionEntity)); + } + return response; + } else { + return null; + } + } else { + return null; + } + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionJsonEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionJsonEndpoint.java new file mode 100644 index 0000000000..90bdedc78b --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionJsonEndpoint.java @@ -0,0 +1,45 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; + +/** + * Created by gvagenas on 1/19/16. + */ + +@Path("/Accounts/{accountSid}/Version.json") +@ThreadSafe +public class VersionJsonEndpoint extends VersionEndpoint { + + @GET + public Response getVersion(@PathParam("accountSid") final String accountSid) { + return getVersion(accountSid, APPLICATION_JSON_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionXmlEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionXmlEndpoint.java new file mode 100644 index 0000000000..a3b110d49d --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/VersionXmlEndpoint.java @@ -0,0 +1,44 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http; + +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; + +/** + * Created by gvagenas on 1/19/16. + */ +@Path("/Accounts/{accountSid}/Version") +@ThreadSafe +public class VersionXmlEndpoint extends VersionEndpoint { + + @GET + public Response getVersion(@PathParam("accountSid") final String accountSid) { + return getVersion(accountSid, APPLICATION_XML_TYPE); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/asyncclient/HttpAsycClientHelper.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/asyncclient/HttpAsycClientHelper.java new file mode 100644 index 0000000000..cec8ff0468 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/asyncclient/HttpAsycClientHelper.java @@ -0,0 +1,227 @@ +/* + * 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.asyncclient; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.util.StringUtils; +import org.restcomm.connect.http.client.DownloaderResponse; +import org.restcomm.connect.http.client.HttpRequestDescriptor; +import org.restcomm.connect.http.client.HttpResponseDescriptor; + +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; + +/** + * @author maria.farooq + */ +public final class HttpAsycClientHelper extends RestcommUntypedActor { + + public static final int LOGGED_RESPONSE_MAX_SIZE = 100; + + private CloseableHttpAsyncClient client = null; + + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + public HttpAsycClientHelper () { + super(); + client = (CloseableHttpAsyncClient) CustomHttpClientBuilder.buildCloseableHttpAsyncClient(RestcommConfiguration.getInstance().getMain()); + } + + @Override + public void onReceive (final Object message) throws Exception { + final Class klass = message.getClass(); + final ActorRef sender = sender(); + if (logger.isInfoEnabled()) { + logger.info(" ********** HttpAsycClientHelper " + self().path() + " Sender: " + sender); + logger.info(" ********** HttpAsycClientHelper " + self().path() + " Processing Message: " + klass.getName()); + } + if (HttpRequestDescriptor.class.equals(klass)) { + final HttpRequestDescriptor request = (HttpRequestDescriptor) message; + if (logger.isDebugEnabled()) { + logger.debug("New HttpRequestDescriptor, method: " + request.getMethod() + " URI: " + request.getUri() + " parameters: " + request.getParametersAsString()); + } + try { + execute(request, sender); + } catch (final Exception exception) { + DownloaderResponse response = new DownloaderResponse(exception, "Problem while trying to exceute request"); + sender.tell(response, self()); + } + } + } + + + public void execute (final HttpRequestDescriptor descriptor, ActorRef sender) throws IllegalArgumentException, IOException, + URISyntaxException, XMLStreamException { + HttpUriRequest request = null; + HttpRequestDescriptor temp = descriptor; + try { + + request = request(temp); + request.setHeader("http.protocol.content-charset", "UTF-8"); + if (descriptor.getTimeout() > 0){ + HttpContext httpContext = new BasicHttpContext(); + httpContext.setAttribute(HttpClientContext.REQUEST_CONFIG, RequestConfig.custom(). + setConnectTimeout(descriptor.getTimeout()). + setSocketTimeout(descriptor.getTimeout()). + setConnectionRequestTimeout(descriptor.getTimeout()).build()); + client.execute(request, httpContext, getFutureCallback(request, sender)); + } else { + client.execute(request, getFutureCallback(request, sender)); + } + } catch (Exception e) { + logger.error("Problem while trying to execute http request {}, exception: {}", request.getRequestLine(), e); + throw e; + } + } + + private FutureCallback getFutureCallback(final HttpUriRequest request, final ActorRef sender){ + return new FutureCallback(){ + + @Override + public void completed(HttpResponse result) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("success on execution of http request. result %s", result)); + } + DownloaderResponse response = null; + try { + response = new DownloaderResponse(response(request, result)); + } catch (IOException e) { + logger.error("Exception while parsing response", e); + response = new DownloaderResponse(e, "Exception while parsing response"); + } + sender.tell(response, self()); + } + + @Override + public void failed(Exception ex) { + logger.error("got failure on executing http request {}, exception: {}", request.getRequestLine(), ex); + DownloaderResponse response = new DownloaderResponse(ex, "got failure on executing http request"); + sender.tell(response, self()); + } + + @Override + public void cancelled() { + logger.warning("got cancellation on executing http request {}", request.getRequestLine()); + DownloaderResponse response = new DownloaderResponse(new Exception("got cancellation on executing http request"), "got cancellation on executing http request"); + sender.tell(response, self()); + }}; + } + + public HttpUriRequest request (final HttpRequestDescriptor descriptor) throws IllegalArgumentException, URISyntaxException, + UnsupportedEncodingException { + final URI uri = descriptor.getUri(); + final String method = descriptor.getMethod(); + HttpUriRequest httpUriRequest = null; + if ("GET".equalsIgnoreCase(method)) { + final String query = descriptor.getParametersAsString(); + URI result = null; + if (query != null && !query.isEmpty()) { + result = new URIBuilder() + .setScheme(uri.getScheme()) + .setHost(uri.getHost()) + .setPort(uri.getPort()) + .setPath(uri.getPath()) + .setQuery(query) + .build(); + } else { + result = uri; + } + httpUriRequest = new HttpGet(result); + } else if ("POST".equalsIgnoreCase(method)) { + final List parameters = descriptor.getParameters(); + final HttpPost post = new HttpPost(uri); + post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8")); + httpUriRequest = post; + } else { + throw new IllegalArgumentException(method + " is not a supported downloader method."); + } + if(descriptor.getHeaders() != null && descriptor.getHeaders().length>0){ + httpUriRequest.setHeaders(descriptor.getHeaders()); + } + return httpUriRequest; + } + + private HttpResponseDescriptor response (final HttpRequest request, final HttpResponse response) throws IOException { + final HttpResponseDescriptor.Builder builder = HttpResponseDescriptor.builder(); + final URI uri = URI.create(request.getRequestLine().getUri()); + builder.setURI(uri); + builder.setStatusCode(response.getStatusLine().getStatusCode()); + builder.setStatusDescription(response.getStatusLine().getReasonPhrase()); + builder.setHeaders(response.getAllHeaders()); + final HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream stream = entity.getContent(); + try { + final Header contentEncoding = entity.getContentEncoding(); + if (contentEncoding != null) { + builder.setContentEncoding(contentEncoding.getValue()); + } + final Header contentType = entity.getContentType(); + if (contentType != null) { + builder.setContentType(contentType.getValue()); + } + builder.setContent(StringUtils.toString(stream)); + builder.setContentLength(entity.getContentLength()); + builder.setIsChunked(entity.isChunked()); + } finally { + stream.close(); + } + } + return builder.build(); + } + + @Override + public void postStop () { + if (logger.isDebugEnabled()) { + logger.debug("HttpAsycClientHelper at post stop"); + } + getContext().stop(self()); + super.postStop(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/CallApiResponse.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/CallApiResponse.java new file mode 100644 index 0000000000..28d1b605b4 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/CallApiResponse.java @@ -0,0 +1,39 @@ +/* + * 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; + +import org.restcomm.connect.commons.patterns.StandardResponse; + +/** + * @author Maria Farooq + */ +public final class CallApiResponse extends StandardResponse { + public CallApiResponse(final HttpResponseDescriptor object) { + super(object); + } + + public CallApiResponse(final Throwable cause) { + super(cause); + } + + public CallApiResponse(final Throwable cause, final String message) { + super(cause, message); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/Downloader.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/Downloader.java new file mode 100644 index 0000000000..7add39ca98 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/Downloader.java @@ -0,0 +1,264 @@ +/* + * 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; + +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.util.StringUtils; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLStreamException; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public final class Downloader extends RestcommUntypedActor { + + public static final int LOGGED_RESPONSE_MAX_SIZE = 100; + + private CloseableHttpClient client = null; + + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + public Downloader () { + super(); + client = (CloseableHttpClient) CustomHttpClientBuilder.buildDefaultClient(RestcommConfiguration.getInstance().getMain()); + } + + + public HttpResponseDescriptor fetch (final HttpRequestDescriptor descriptor) throws IllegalArgumentException, IOException, + URISyntaxException, XMLStreamException { + int code = -1; + HttpRequest request = null; + CloseableHttpResponse response = null; + HttpRequestDescriptor temp = descriptor; + HttpResponseDescriptor responseDescriptor = null; + HttpResponseDescriptor rawResponseDescriptor = null; + try { + do { + request = request(temp); + request.setHeader("http.protocol.content-charset", "UTF-8"); + if (descriptor.getTimeout() > 0){ + HttpContext httpContext = new BasicHttpContext(); + httpContext.setAttribute(HttpClientContext.REQUEST_CONFIG, RequestConfig.custom(). + setConnectTimeout(descriptor.getTimeout()). + setSocketTimeout(descriptor.getTimeout()). + setConnectionRequestTimeout(descriptor.getTimeout()).build()); + response = client.execute((HttpUriRequest) request, httpContext); + } else { + response = client.execute((HttpUriRequest) request); + } + code = response.getStatusLine().getStatusCode(); + if (isRedirect(code)) { + final Header header = response.getFirstHeader(HttpHeaders.LOCATION); + if (header != null) { + final String location = header.getValue(); + final URI uri = URI.create(location); + temp = new HttpRequestDescriptor(uri, temp.getMethod(), temp.getParameters()); + continue; + } else { + break; + } + } +// HttpResponseDescriptor httpResponseDescriptor = response(request, response); + rawResponseDescriptor = response(request, response); + responseDescriptor = validateXML(rawResponseDescriptor); + } while (isRedirect(code)); + if (isHttpError(code)) { + // TODO - usually this part of code is not reached. Error codes are part of error responses that do not pass validateXML above and an exception is thrown. We need to re-thing this + String requestUrl = request.getRequestLine().getUri(); + String errorReason = response.getStatusLine().getReasonPhrase(); + String httpErrorMessage = String.format( + "Problem while fetching http resource: %s \n Http status code: %d \n Http status message: %s", requestUrl, + code, errorReason); + logger.warning(httpErrorMessage); + } + } catch (Exception e) { + logger.warning("Problem while trying to download RCML from {}, exception: {}", request.getRequestLine(), e); + String statusInfo = "n/a"; + String responseInfo = "n/a"; + if (response != null) { + // Build additional information to log. Include http status, url and a small fragment of the response. + statusInfo = response.getStatusLine().toString(); + if (rawResponseDescriptor != null) { + int truncatedSize = (int) Math.min(rawResponseDescriptor.getContentLength(), LOGGED_RESPONSE_MAX_SIZE); + if (rawResponseDescriptor.getContentAsString() != null) { + responseInfo = String.format("%s %s", rawResponseDescriptor.getContentAsString().substring(0, truncatedSize), (rawResponseDescriptor.getContentLength() < LOGGED_RESPONSE_MAX_SIZE ? "" : "...")); + } + } + } + logger.warning(String.format("Problem while trying to download RCML. URL: %s, Status: %s, Response: %s ", request.getRequestLine(), statusInfo, responseInfo)); + throw e; // re-throw + } finally { + if (response != null) { + response.close(); + } + } + return responseDescriptor; + } + + private boolean isRedirect (final int code) { + return HttpStatus.SC_MOVED_PERMANENTLY == code || HttpStatus.SC_MOVED_TEMPORARILY == code + || HttpStatus.SC_SEE_OTHER == code || HttpStatus.SC_TEMPORARY_REDIRECT == code; + } + + private boolean isHttpError (final int code) { + return (code >= 400); + } + + private HttpResponseDescriptor validateXML (final HttpResponseDescriptor descriptor) throws XMLStreamException { + if (descriptor.getContentLength() > 0) { + try { + // parse an XML document into a DOM tree + String xml = descriptor.getContentAsString().trim().replaceAll("&([^;]+(?!(?:\\w|;)))", "&$1"); + DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + parser.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); + return descriptor; + } catch (final Exception e) { + throw new XMLStreamException("Error parsing the RCML:" + e); + } + } + return descriptor; + } + + @Override + public void onReceive (final Object message) throws Exception { + final Class klass = message.getClass(); + final ActorRef self = self(); + final ActorRef sender = sender(); + if (HttpRequestDescriptor.class.equals(klass)) { + final HttpRequestDescriptor request = (HttpRequestDescriptor) message; + if (logger.isDebugEnabled()) { + logger.debug("New HttpRequestDescriptor, method: " + request.getMethod() + " URI: " + request.getUri() + " parameters: " + request.getParametersAsString()); + } + DownloaderResponse response = null; + try { + response = new DownloaderResponse(fetch(request)); + } catch (final Exception exception) { + response = new DownloaderResponse(exception, "Problem while trying to download RCML"); + } + if (sender != null && !sender.isTerminated()) { + sender.tell(response, self); + } else { + if (logger.isInfoEnabled()) { + logger.info("DownloaderResponse wont be send because sender is :" + (sender.isTerminated() ? "terminated" : "null")); + } + } + } + } + + public HttpUriRequest request (final HttpRequestDescriptor descriptor) throws IllegalArgumentException, URISyntaxException, + UnsupportedEncodingException { + final URI uri = descriptor.getUri(); + final String method = descriptor.getMethod(); + if ("GET".equalsIgnoreCase(method)) { + final String query = descriptor.getParametersAsString(); + URI result = null; + if (query != null && !query.isEmpty()) { + result = new URIBuilder() + .setScheme(uri.getScheme()) + .setHost(uri.getHost()) + .setPort(uri.getPort()) + .setPath(uri.getPath()) + .setQuery(query) + .build(); + } else { + result = uri; + } + return new HttpGet(result); + } else if ("POST".equalsIgnoreCase(method)) { + final List parameters = descriptor.getParameters(); + final HttpPost post = new HttpPost(uri); + post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8")); + return post; + } else { + throw new IllegalArgumentException(method + " is not a supported downloader method."); + } + } + + private HttpResponseDescriptor response (final HttpRequest request, final HttpResponse response) throws IOException { + final HttpResponseDescriptor.Builder builder = HttpResponseDescriptor.builder(); + final URI uri = URI.create(request.getRequestLine().getUri()); + builder.setURI(uri); + builder.setStatusCode(response.getStatusLine().getStatusCode()); + builder.setStatusDescription(response.getStatusLine().getReasonPhrase()); + builder.setHeaders(response.getAllHeaders()); + final HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream stream = entity.getContent(); + try { + final Header contentEncoding = entity.getContentEncoding(); + if (contentEncoding != null) { + builder.setContentEncoding(contentEncoding.getValue()); + } + final Header contentType = entity.getContentType(); + if (contentType != null) { + builder.setContentType(contentType.getValue()); + } + builder.setContent(StringUtils.toString(stream)); + builder.setContentLength(entity.getContentLength()); + builder.setIsChunked(entity.isChunked()); + } finally { + stream.close(); + } + } + return builder.build(); + } + + @Override + public void postStop () { + if (logger.isDebugEnabled()) { + logger.debug("Downloader at post stop"); + } + super.postStop(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/DownloaderResponse.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/DownloaderResponse.java similarity index 91% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/DownloaderResponse.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/DownloaderResponse.java index 76e07deba4..8e80392d01 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/DownloaderResponse.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/DownloaderResponse.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.client; +package org.restcomm.connect.http.client; -import org.mobicents.servlet.restcomm.patterns.StandardResponse; +import org.restcomm.connect.commons.patterns.StandardResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpRequestDescriptor.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpRequestDescriptor.java similarity index 77% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpRequestDescriptor.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpRequestDescriptor.java index f759958c2a..34863a262f 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpRequestDescriptor.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpRequestDescriptor.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.client; +package org.restcomm.connect.http.client; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -25,10 +25,11 @@ import java.util.ArrayList; import java.util.List; +import org.apache.http.Header; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -38,9 +39,14 @@ public final class HttpRequestDescriptor { private final URI uri; private final String method; private final List parameters; + private final Integer timeout; + private final Header[] headers; - public HttpRequestDescriptor(final URI uri, final String method, final List parameters) { + public HttpRequestDescriptor(final URI uri, final String method, + final List parameters, + final Integer timeout, final Header[] headers) { super(); + this.timeout = timeout; this.uri = base(uri); this.method = method; if (parameters != null) { @@ -53,6 +59,18 @@ public HttpRequestDescriptor(final URI uri, final String method, final List other = URLEncodedUtils.parse(uri, "UTF-8"); parameters.addAll(other); } + this.headers = headers; + + } + + public HttpRequestDescriptor(final URI uri, final String method, + final List parameters, + final Integer timeout){ + this(uri, method, parameters, timeout, null); + } + + public HttpRequestDescriptor(final URI uri, final String method, final List parameters) { + this(uri,method,parameters, -1); } public HttpRequestDescriptor(final URI uri, final String method) throws UnsupportedEncodingException, URISyntaxException { @@ -92,4 +110,13 @@ public String getParametersAsString() { public URI getUri() { return uri; } + + public Integer getTimeout() { + return timeout; + } + + public Header[] getHeaders() { + return headers; + } + } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpResponseDescriptor.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpResponseDescriptor.java similarity index 82% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpResponseDescriptor.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpResponseDescriptor.java index 0fc9d0ca83..22442685bd 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/client/HttpResponseDescriptor.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/HttpResponseDescriptor.java @@ -17,17 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.client; +package org.restcomm.connect.http.client; import java.io.IOException; -import java.io.InputStream; import java.net.URI; import org.apache.http.Header; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.util.HttpUtils; -import org.mobicents.servlet.restcomm.util.StringUtils; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.util.HttpUtils; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -37,17 +35,15 @@ public final class HttpResponseDescriptor { private final URI uri; private final int statusCode; private final String statusDescription; - private final InputStream content; + private final String content; private final long contentLength; private final String contentEncoding; private final String contentType; private final boolean isChunked; private final Header[] headers; - private volatile String buffer; - private HttpResponseDescriptor(final URI uri, final int statusCode, final String statusDescription, - final InputStream content, final long contentLength, final String contentEncoding, final String contentType, + final String content, final long contentLength, final String contentEncoding, final String contentType, final boolean isChunked, final Header[] headers) { super(); this.uri = uri; @@ -69,21 +65,22 @@ public String getStatusDescription() { return statusDescription; } - public InputStream getContent() { - return content; - } +// public InputStream getContent() { +// return content; +// } public String getContentAsString() throws IOException { - if (buffer != null) { - return buffer; - } else { - synchronized (this) { - if (buffer == null) { - buffer = StringUtils.toString(content); - } - } - return buffer; - } +// if (buffer != null) { +// return buffer; +// } else { +// synchronized (this) { +// if (buffer == null) { +// buffer = StringUtils.toString(content); +// } +// } +// return buffer; +// } + return content; } public long getContentLength() { @@ -122,7 +119,7 @@ public static final class Builder { private URI uri; private int statusCode; private String statusDescription; - private InputStream content; + private String content; private long contentLength; private String contentEncoding; private String contentType; @@ -146,7 +143,7 @@ public void setStatusDescription(final String statusDescription) { this.statusDescription = statusDescription; } - public void setContent(final InputStream content) { + public void setContent(final String content) { this.content = content; } diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/CallApiClient.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/CallApiClient.java new file mode 100644 index 0000000000..9212c6b768 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/CallApiClient.java @@ -0,0 +1,172 @@ +/* + * 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.api; + +import java.net.URI; +import java.net.URISyntaxException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import org.apache.http.Header; +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +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.DaoManager; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.http.asyncclient.HttpAsycClientHelper; +import org.restcomm.connect.http.client.CallApiResponse; +import org.restcomm.connect.http.client.DownloaderResponse; +import org.restcomm.connect.http.client.HttpRequestDescriptor; +import org.restcomm.connect.telephony.api.Hangup; + +import akka.actor.ActorRef; +import akka.actor.Props; +import akka.actor.ReceiveTimeout; +import akka.actor.UntypedActor; +import akka.actor.UntypedActorFactory; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import scala.concurrent.duration.Duration; + +/** + * @author mariafarooq + * Disposable call api client to be used for one request and get destroyed after that. + * + */ +public class CallApiClient extends RestcommUntypedActor { + + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + private final DaoManager storage; + private final Sid callSid; + private CallDetailRecord callDetailRecord; + private ActorRef requestee; + + private ActorRef httpAsycClientHelper; + + /** + * @param callSid + * @param storage + */ + public CallApiClient(final Sid callSid, final DaoManager storage) { + super(); + this.callSid = callSid; + this.storage = storage; + //actor will only live in memory for one hour + context().setReceiveTimeout(Duration.create(3600, TimeUnit.SECONDS)); + } + @Override + public void onReceive(Object message) throws Exception { + final Class klass = message.getClass(); + final ActorRef sender = sender(); + ActorRef self = self(); + + if (logger.isInfoEnabled()) { + logger.info(" ********** CallApiClient " + self().path() + " Sender: " + sender); + logger.info(" ********** CallApiClient " + self().path() + " Processing Message: " + klass.getName()); + } + if (Hangup.class.equals(klass)) { + onHangup((Hangup) message, self, sender); + } else if (DownloaderResponse.class.equals(klass)) { + onDownloaderResponse(message, self, sender); + } else if (message instanceof ReceiveTimeout) { + onDownloaderResponse(new DownloaderResponse(new Exception("Call Api stayed active too long")), self, sender); + getContext().stop(self()); + } + } + + private void onDownloaderResponse(Object message, ActorRef self, ActorRef sender) { + final DownloaderResponse response = (DownloaderResponse) message; + if (logger.isInfoEnabled()) { + logger.info("Call api response succeeded " + response.succeeded()); + logger.info("Call api response: " + response); + } + requestee = requestee == null ? sender : requestee; + CallApiResponse apiResponse; + if (response.succeeded()) { + apiResponse = new CallApiResponse(response.get()); + } else { + apiResponse = new CallApiResponse(response.cause(), response.error()); + } + requestee.tell(apiResponse, self); + } + + protected void onHangup(Hangup message, ActorRef self, ActorRef sender) throws URISyntaxException, ParseException { + requestee = sender; + callDetailRecord = message.getCallDetailRecord() == null ? getCallDetailRecord() : message.getCallDetailRecord(); + if(callDetailRecord == null){ + logger.error("could not retrieve cdr by provided Sid"); + onDownloaderResponse(new DownloaderResponse(new IllegalArgumentException("could not retrieve cdr by provided Sid")), self, sender); + } else { + try { + URI uri = new URI("/restcomm"+callDetailRecord.getUri()); + uri = UriUtils.resolve(uri); + if (logger.isInfoEnabled()) + logger.info("call api uri is: "+uri); + + Header[] headers = RestcommApiClientUtil.getBasicHeaders(message.getRequestingAccountSid(), storage); + + ArrayList postParameters = new ArrayList(); + postParameters.add(new BasicNameValuePair("Status", "Completed")); + + httpAsycClientHelper = httpAsycClientHelper(); + HttpRequestDescriptor httpRequestDescriptor =new HttpRequestDescriptor(uri, "POST", postParameters, -1, headers); + httpAsycClientHelper.tell(httpRequestDescriptor, self); + } catch (Exception e) { + logger.error("Exception while trying to terminate call via api {} ", e); + onDownloaderResponse(new DownloaderResponse(e), self, sender); + } + } + } + + private CallDetailRecord getCallDetailRecord() { + if(callSid != null){ + return storage.getCallDetailRecordsDao().getCallDetailRecord(callSid); + } + return null; + } + + private ActorRef httpAsycClientHelper(){ + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new HttpAsycClientHelper(); + } + }); + return getContext().actorOf(props); + + } + + @Override + public void postStop () { + if (logger.isInfoEnabled()) { + logger.info("CallApiClient at post stop"); + } + if(httpAsycClientHelper != null && !httpAsycClientHelper.isTerminated()) + getContext().stop(httpAsycClientHelper); + getContext().stop(self()); + super.postStop(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/RestcommApiClientUtil.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/RestcommApiClientUtil.java new file mode 100644 index 0000000000..8e1c158753 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/api/RestcommApiClientUtil.java @@ -0,0 +1,60 @@ +/* + * 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.api; + +import java.nio.charset.Charset; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.Header; +import org.apache.http.HttpHeaders; +import org.apache.http.message.BasicHeader; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; + +/** + * @author maria.farooq + */ +public final class RestcommApiClientUtil { + + public static String getAuthenticationHeader(Sid sid, DaoManager storage) { + Account requestingAccount = storage.getAccountsDao().getAccount(sid); + + String authenticationHeader = null; + if(requestingAccount != null) { + String auth = requestingAccount.getSid() + ":" + requestingAccount.getAuthToken(); + byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("ISO-8859-1"))); + authenticationHeader = "Basic " + new String(encodedAuth); + } + return authenticationHeader; + } + + public static Header[] getBasicHeaders(Sid sid, DaoManager storage){ + Header authHeader = new BasicHeader(HttpHeaders.AUTHORIZATION, RestcommApiClientUtil.getAuthenticationHeader(sid, storage)); + Header contentTypeHeader = new BasicHeader("Content-type", "application/x-www-form-urlencoded"); + Header acceptHeader = new BasicHeader("Accept", "application/json"); + Header[] headers = { + authHeader + , contentTypeHeader + , acceptHeader + }; + return headers; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverApi.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverApi.java new file mode 100644 index 0000000000..070b8c72cf --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverApi.java @@ -0,0 +1,148 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder; +import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; +import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet; +import org.restcomm.connect.commons.util.SecurityUtils; +import org.restcomm.connect.commons.util.UriUtils; +import org.restcomm.connect.dao.entities.Account; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.restcomm.connect.dao.entities.Account.Status; + +/** + * Utility class that handles notification submission to rcmlserver (typically + * RVD) + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RcmlserverApi { + + static final Logger logger = Logger.getLogger(RcmlserverApi.class.getName()); + + enum NotificationType { + accountClosed, accountSuspended, + accountActivated, accountUninitialized, + accountInactivated + } + + private static final Map status2NotMap = new HashMap(); + static { + status2NotMap.put(Status.CLOSED, NotificationType.accountClosed); + status2NotMap.put(Status.ACTIVE, NotificationType.accountActivated); + status2NotMap.put(Status.SUSPENDED, NotificationType.accountSuspended); + status2NotMap.put(Status.INACTIVE, NotificationType.accountInactivated); + status2NotMap.put(Status.UNINITIALIZED, NotificationType.accountUninitialized); + } + + URI apiUrl; + MainConfigurationSet mainConfig; + RcmlserverConfigurationSet rcmlserverConfig; + + public RcmlserverApi(MainConfigurationSet mainConfig, RcmlserverConfigurationSet rcmlserverConfig) { + try { + // if there is no baseUrl configured we use the resolver to guess the location of the rcml server and the path + if (StringUtils.isEmpty(rcmlserverConfig.getBaseUrl())) { + // resolve() should be run lazily to work. Make sure this constructor is invoked after the JBoss connectors have been set up. + apiUrl = UriUtils.resolve(new URI(rcmlserverConfig.getApiPath())); + } // if baseUrl has been configured, concat baseUrl and path to find the location of rcml server. No resolving here. + else { + String path = rcmlserverConfig.getApiPath(); + apiUrl = new URI(rcmlserverConfig.getBaseUrl() + (path != null ? path : "")); + } + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + this.rcmlserverConfig = rcmlserverConfig; + this.mainConfig = mainConfig; + } + + class RCMLCallback implements FutureCallback { + + @Override + public void completed(HttpResponse t) { + logger.debug("RVD notification sent"); + } + + @Override + public void failed(Exception excptn) { + logger.error("RVD notification failed", excptn); + } + + @Override + public void cancelled() { + logger.debug("RVD notification cancelled"); + } + + } + + public void transmitNotifications(List notifications, String notifierUsername, String notifierPassword) { + String notificationUrl = apiUrl + "/notifications"; + HttpPost request = new HttpPost(notificationUrl); + String authHeader; + authHeader = SecurityUtils.buildBasicAuthHeader(notifierUsername, notifierPassword); + request.setHeader("Authorization", authHeader); + Gson gson = new Gson(); + String json = gson.toJson(notifications); + request.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); + Integer totalTimeout = rcmlserverConfig.getTimeout() + notifications.size() * rcmlserverConfig.getTimeoutPerNotification(); + CloseableHttpAsyncClient httpClient = CustomHttpClientBuilder.buildCloseableHttpAsyncClient(mainConfig); + if (logger.isDebugEnabled()) { + logger.debug("Will transmit a set of " + + notifications.size() + " " + + "notifications and wait at most for " + + totalTimeout); + } + HttpContext httpContext = new BasicHttpContext(); + httpContext.setAttribute(HttpClientContext.REQUEST_CONFIG, RequestConfig.custom(). + setConnectTimeout(totalTimeout). + setSocketTimeout(totalTimeout). + setConnectionRequestTimeout(totalTimeout).build()); + httpClient.execute(request, httpContext, new RCMLCallback()); + } + + public JsonObject buildAccountStatusNotification(Account account) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("type", status2NotMap.get(account.getStatus()).toString()); + jsonObject.addProperty("accountSid", account.getSid().toString()); + return jsonObject; + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverNotifications.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverNotifications.java new file mode 100644 index 0000000000..01009bd154 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/RcmlserverNotifications.java @@ -0,0 +1,31 @@ +/* + * 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; + +import com.google.gson.JsonObject; + +import java.util.ArrayList; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RcmlserverNotifications extends ArrayList { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java new file mode 100644 index 0000000000..628f20e6ac --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java @@ -0,0 +1,93 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2014, Telestax Inc and individual contributors + * by the @authors tag. + * + * This program is free software: you can redistribute it and/or modify + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +package org.restcomm.connect.http.client.rcmlserver.resolver; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A relative URI resolver for Rcmlserver/RVD. It values defined in rcmlserver restcomm.xml configuration + * section (rcmlserver.base-url, rcmlserver.api-path) to convert relative urls to absolute i.e. prepent Rcmlserver origin (http://rcmlserver.domain:port). + * By design, the resolver is used when resolving Application.rcmlUrl only. An additional filter prefix + * is used and helps the resolver affect only urls that start with "/restcomm-rvd/". This filter value is + * configurable through rcmlserver.api-path. It will use whatever it between the first pair of slashes "/.../". + * If configuration is missing or rcmlserver is deployed bundled with restcomm the resolver won't affect the + * uri resolved, typically leaving UriUtils class take care of it. + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RcmlserverResolver { + protected static Logger logger = Logger.getLogger(RcmlserverResolver.class); + static RcmlserverResolver singleton; + + String rvdOrigin; + String filterPrefix; // a pattern used to match against relative urls in application.rcmlUrl. If null, to resolving will occur. + + static final String DEFAULT_FILTER_PREFIX = "/restcomm-rvd/"; + + // not really a clean singleton pattern but a way to init once and use many. Only the first time this method is called the parameters are used in the initialization + public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath, boolean reinit) { + if (singleton == null || reinit) { + singleton = new RcmlserverResolver(rvdOrigin, apiPath); + } + return singleton; + } + + public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath) { + return getInstance(rvdOrigin, apiPath, false); + } + + public RcmlserverResolver(String rvdOrigin, String apiPath) { + this.rvdOrigin = rvdOrigin; + if ( ! StringUtils.isEmpty(apiPath) ) { + // extract the first part of the path and use it as a filter prefix + Pattern pattern = Pattern.compile("/([^/]*)((/.*)|$)"); + Matcher matcher = pattern.matcher(apiPath); + if (matcher.matches() && matcher.group(1) != null) { + filterPrefix = "/" + matcher.group(1) + "/"; + } else + filterPrefix = DEFAULT_FILTER_PREFIX; + logger.info("RcmlserverResolver initialized. Urls starting with '" + filterPrefix + "' will get prepended with '" + (rvdOrigin == null ? "" : rvdOrigin) + "'"); + } else + filterPrefix = null; + } + + // if rvdOrigin is null no point in trying to resolve RVD location. We will return passed uri instead + public URI resolveRelative(URI uri) { + if (uri != null && rvdOrigin != null && filterPrefix != null) { + if (uri.isAbsolute()) + return uri; + try { + String uriString = uri.toString(); + if (uriString.startsWith(filterPrefix)) + return new URI(rvdOrigin + uri.toString()); + } catch (URISyntaxException e) { + logger.error("Cannot resolve uri: " + uri.toString() + ". Ignoring...", e); + } + } + return uri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AbstractConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AbstractConverter.java new file mode 100644 index 0000000000..a78f6473bc --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AbstractConverter.java @@ -0,0 +1,666 @@ +/* + * 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.converter; + +import java.math.BigDecimal; +import java.net.URI; +import java.text.SimpleDateFormat; +import java.util.Currency; +import java.util.Locale; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.dao.Sid; + +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + * @author gvagenas + * @author Jean Deruelle + */ +public abstract class AbstractConverter implements Converter { + protected final Configuration configuration; + + public AbstractConverter(final Configuration configuration) { + super(); + this.configuration = configuration; + } + + @SuppressWarnings("rawtypes") + @Override + public abstract boolean canConvert(Class klass); + + @Override + public abstract void marshal(final Object object, HierarchicalStreamWriter writer, MarshallingContext context); + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + return null; + } + + protected void writeAccountSid(final Sid accountSid, final HierarchicalStreamWriter writer) { + if (accountSid != null) { + writer.startNode("AccountSid"); + writer.setValue(accountSid.toString()); + writer.endNode(); + } + } + + protected void writeAccountSid(final Sid accountSid, final JsonObject object) { + if (accountSid != null) { + object.addProperty("account_sid", accountSid.toString()); + } else { + object.add("account_sid", JsonNull.INSTANCE); + } + } + + protected void writeApiVersion(final String apiVersion, final HierarchicalStreamWriter writer) { + writer.startNode("ApiVersion"); + writer.setValue(apiVersion); + writer.endNode(); + } + + protected void writeApiVersion(final String apiVersion, final JsonObject object) { + object.addProperty("api_version", apiVersion); + } + + protected void writeCallSid(final Sid callSid, final HierarchicalStreamWriter writer) { + if (callSid != null) { + writer.startNode("CallSid"); + writer.setValue(callSid.toString()); + writer.endNode(); + } + } + + protected void writeCallSid(final Sid callSid, final JsonObject object) { + if (callSid != null) + object.addProperty("call_sid", callSid.toString()); + } + + protected void writeDateCreated(final DateTime dateCreated, final HierarchicalStreamWriter writer) { + writer.startNode("DateCreated"); + writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateCreated.toDate())); + writer.endNode(); + } + + protected void writeDateCreated(final DateTime dateCreated, final JsonObject object) { + object.addProperty("date_created", + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateCreated.toDate())); + } + + protected void writeDateUpdated(final DateTime dateUpdated, final HierarchicalStreamWriter writer) { + writer.startNode("DateUpdated"); + writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateUpdated.toDate())); + writer.endNode(); + } + + protected void writeDateUpdated(final DateTime dateUpdated, final JsonObject object) { + object.addProperty("date_updated", + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateUpdated.toDate())); + } + + protected void writeDuration(final double duration, final HierarchicalStreamWriter writer) { + writer.startNode("Duration"); + writer.setValue(Double.toString(duration)); + writer.endNode(); + } + + protected void writeDuration(final double duration, final JsonObject object) { + object.addProperty("duration", Double.toString(duration)); + } + + protected void writeFriendlyName(final String friendlyName, final HierarchicalStreamWriter writer) { + writer.startNode("FriendlyName"); + writer.setValue(friendlyName); + writer.endNode(); + } + + protected void writeFriendlyName(final String friendlyName, final JsonObject object) { + object.addProperty("friendly_name", friendlyName); + } + + protected void writeFrom(final String from, final HierarchicalStreamWriter writer) { + writer.startNode("From"); + writer.setValue(from); + writer.endNode(); + } + + protected void writeFrom(final String from, final JsonObject object) { + object.addProperty("from", from); + } + + protected void writePhoneNumber(final String phoneNumber, final HierarchicalStreamWriter writer) { + writer.startNode("PhoneNumber"); + writer.setValue(phoneNumber); + writer.endNode(); + } + + protected void writePhoneNumber(final String phoneNumber, final JsonObject object) { + object.addProperty("phone_number", phoneNumber); + } + + protected void writePrice(final BigDecimal price, final HierarchicalStreamWriter writer) { + writer.startNode("Price"); + writer.setValue(price.toString()); + writer.endNode(); + } + + protected void writePrice(final BigDecimal price, final JsonObject object) { + object.addProperty("price", price.toString()); + } + + protected void writePriceUnit(final Currency priceUnit, final HierarchicalStreamWriter writer) { + writer.startNode("PriceUnit"); + if (priceUnit != null) { + writer.setValue(priceUnit.toString()); + } + writer.endNode(); + } + + protected void writePriceUnit(final Currency priceUnit, final JsonObject object) { + if (priceUnit != null) { + object.addProperty("price_unit", priceUnit.toString()); + } else { + object.add("price_unit", JsonNull.INSTANCE); + } + } + + protected void writeSid(final Sid sid, final HierarchicalStreamWriter writer) { + writer.startNode("Sid"); + writer.setValue(sid.toString()); + writer.endNode(); + } + + protected void writeSid(final Sid sid, final JsonObject object) { + object.addProperty("sid", sid.toString()); + } + + protected void writeDomainName(final String domainName, final HierarchicalStreamWriter writer) { + writer.startNode("DomainName"); + writer.setValue(domainName); + writer.endNode(); + } + + protected void writeDomainName(final String domainName, final JsonObject object) { + object.addProperty("domain_name", domainName); + } + + protected void writeSmsFallbackUrl(final URI smsFallbackUrl, final HierarchicalStreamWriter writer) { + if (smsFallbackUrl != null) { + writer.startNode("SmsFallbackUrl"); + writer.setValue(smsFallbackUrl.toString()); + writer.endNode(); + } + } + + protected void writeSmsFallbackUrl(final URI smsFallbackUrl, final JsonObject object) { + if (smsFallbackUrl != null) { + object.addProperty("sms_fallback_url", smsFallbackUrl.toString()); + } else { + object.add("sms_fallback_url", JsonNull.INSTANCE); + } + } + + protected void writeSmsFallbackMethod(final String smsFallbackMethod, final HierarchicalStreamWriter writer) { + writer.startNode("SmsFallbackMethod"); + if (smsFallbackMethod != null) { + writer.setValue(smsFallbackMethod); + } + writer.endNode(); + } + + protected void writeSmsFallbackMethod(final String smsFallbackMethod, final JsonObject object) { + if (smsFallbackMethod != null) { + object.addProperty("sms_fallback_method", smsFallbackMethod); + } else { + object.add("sms_fallback_method", JsonNull.INSTANCE); + } + } + + protected void writeSmsUrl(final URI smsUrl, final HierarchicalStreamWriter writer) { + if (smsUrl != null) { + writer.startNode("SmsUrl"); + writer.setValue(smsUrl.toString()); + writer.endNode(); + } + } + + protected void writeSmsUrl(final URI smsUrl, final JsonObject object) { + if (smsUrl != null) { + object.addProperty("sms_url", smsUrl.toString()); + } else { + object.add("sms_url", JsonNull.INSTANCE); + } + } + + protected void writeSmsMethod(final String smsMethod, final HierarchicalStreamWriter writer) { + writer.startNode("SmsMethod"); + if (smsMethod != null) { + writer.setValue(smsMethod); + } + writer.endNode(); + } + + protected void writeSmsMethod(final String smsMethod, final JsonObject object) { + if (smsMethod != null) { + object.addProperty("sms_method", smsMethod); + } else { + object.add("sms_method", JsonNull.INSTANCE); + } + } + + protected void writeUssdFallbackUrl(final URI ussdFallbackUrl, final HierarchicalStreamWriter writer) { + if (ussdFallbackUrl != null) { + writer.startNode("UssdFallbackUrl"); + writer.setValue(ussdFallbackUrl.toString()); + writer.endNode(); + } + } + + protected void writeUssdFallbackUrl(final URI ussdFallbackUrl, final JsonObject object) { + if (ussdFallbackUrl != null) { + object.addProperty("ussd_fallback_url", ussdFallbackUrl.toString()); + } else { + object.add("ussd_fallback_url", JsonNull.INSTANCE); + } + } + + protected void writeUssdFallbackMethod(final String ussdFallbackMethod, final HierarchicalStreamWriter writer) { + writer.startNode("UssdFallbackMethod"); + if (ussdFallbackMethod != null) { + writer.setValue(ussdFallbackMethod); + } + writer.endNode(); + } + + protected void writeUssdFallbackMethod(final String ussdFallbackMethod, final JsonObject object) { + if (ussdFallbackMethod != null) { + object.addProperty("ussd_fallback_method", ussdFallbackMethod); + } else { + object.add("ussd_fallback_method", JsonNull.INSTANCE); + } + } + + protected void writeUssdUrl(final URI ussdUrl, final HierarchicalStreamWriter writer) { + if (ussdUrl != null) { + writer.startNode("UssdUrl"); + writer.setValue(ussdUrl.toString()); + writer.endNode(); + } + } + + protected void writeUssdUrl(final URI ussdUrl, final JsonObject object) { + if (ussdUrl != null) { + object.addProperty("ussd_url", ussdUrl.toString()); + } else { + object.add("ussd_url", JsonNull.INSTANCE); + } + } + + protected void writeUssdMethod(final String ussdMethod, final HierarchicalStreamWriter writer) { + writer.startNode("UssdMethod"); + if (ussdMethod != null) { + writer.setValue(ussdMethod); + } + writer.endNode(); + } + + protected void writeUssdMethod(final String ussdMethod, final JsonObject object) { + if (ussdMethod != null) { + object.addProperty("ussd_method", ussdMethod); + } else { + object.add("ussd_method", JsonNull.INSTANCE); + } + } + + protected void writeStatus(final String status, final HierarchicalStreamWriter writer) { + writer.startNode("Status"); + writer.setValue(status); + writer.endNode(); + } + + protected void writeStatus(final String status, final JsonObject object) { + object.addProperty("status", status); + } + + protected void writeStatusCallback(final URI statusCallback, final HierarchicalStreamWriter writer) { + if (statusCallback != null) { + writer.startNode("StatusCallback"); + writer.setValue(statusCallback.toString()); + writer.endNode(); + } + } + + protected void writeStatusCallback(final URI statusCallback, final JsonObject object) { + if (statusCallback != null) { + object.addProperty("status_callback", statusCallback.toString()); + } else { + object.add("status_callback", JsonNull.INSTANCE); + } + } + + protected void writeStatusCallbackMethod(final String statusCallbackMethod, final HierarchicalStreamWriter writer) { + writer.startNode("StatusCallbackMethod"); + if (statusCallbackMethod != null) { + writer.setValue(statusCallbackMethod); + } + writer.endNode(); + } + + protected void writeStatusCallbackMethod(final String statusCallbackMethod, final JsonObject object) { + if (statusCallbackMethod != null) { + object.addProperty("status_callback_method", statusCallbackMethod); + } else { + object.add("status_callback_method", JsonNull.INSTANCE); + } + } + + protected void writeTo(final String to, final HierarchicalStreamWriter writer) { + writer.startNode("To"); + writer.setValue(to); + writer.endNode(); + } + + protected void writeTo(final String to, final JsonObject object) { + object.addProperty("to", to); + } + + protected void writeTimeToLive(final int timeToLive, final HierarchicalStreamWriter writer) { + writer.startNode("TimeToLive"); + writer.setValue(Integer.toString(timeToLive)); + writer.endNode(); + } + + protected void writeTimeToLive(final int timeToLive, final JsonObject object) { + object.addProperty("time_to_live", timeToLive); + } + + protected void writeType(final String type, final HierarchicalStreamWriter writer) { + writer.startNode("Type"); + if (type != null) { + writer.setValue(type); + } else { + writer.setValue(null); + } + writer.endNode(); + } + + protected void writeType(final String type, final JsonObject object) { + object.addProperty("type", type); + } + + protected void writeUri(final URI uri, final HierarchicalStreamWriter writer) { + writer.startNode("Uri"); + writer.setValue(uri.toString()); + writer.endNode(); + } + + protected void writeUri(final URI uri, final JsonObject object) { + object.addProperty("uri", uri.toString() + ".json"); + } + + protected void writeUserName(final String userName, final HierarchicalStreamWriter writer) { + writer.startNode("UserName"); + writer.setValue(userName); + writer.endNode(); + } + + protected void writeUserName(final String userName, final JsonObject object) { + object.addProperty("user_name", userName); + } + + protected void writeVoiceApplicationSid(final Sid voiceApplicationSid, final HierarchicalStreamWriter writer) { + if (voiceApplicationSid != null) { + writer.startNode("VoiceApplicationSid"); + writer.setValue(voiceApplicationSid.toString()); + writer.endNode(); + } + } + + protected void writeVoiceApplicationSid(final Sid voiceApplicationSid, final JsonObject object) { + if (voiceApplicationSid != null) { + object.addProperty("voice_application_sid", voiceApplicationSid.toString()); + } else { + object.add("voice_application_sid", JsonNull.INSTANCE); + } + } + + + protected void writePushClientIdentity(final String pushClientIdentity, final HierarchicalStreamWriter writer) { + if (pushClientIdentity != null) { + writer.startNode("PushClientIdentity"); + writer.setValue(pushClientIdentity); + writer.endNode(); + } + } + + protected void writePushClientIdentity(final String pushClientIdentity, final JsonObject object) { + if (pushClientIdentity != null) { + object.addProperty("push_client_identity", pushClientIdentity); + } else { + object.add("push_client_identity", JsonNull.INSTANCE); + } + } + + protected void writeVoiceCallerIdLookup(final boolean voiceCallerIdLookup, final HierarchicalStreamWriter writer) { + writer.startNode("VoiceCallerIdLookup"); + writer.setValue(Boolean.toString(voiceCallerIdLookup)); + writer.endNode(); + } + + protected void writeVoiceCallerIdLookup(final boolean voiceCallerIdLookup, final JsonObject object) { + object.addProperty("voice_caller_id_lookup", voiceCallerIdLookup); + } + + protected void writeVoiceFallbackMethod(final String voiceFallbackMethod, final HierarchicalStreamWriter writer) { + writer.startNode("VoiceFallbackMethod"); + if (voiceFallbackMethod != null) { + writer.setValue(voiceFallbackMethod); + } + writer.endNode(); + } + + protected void writeVoiceFallbackMethod(final String voiceFallbackMethod, final JsonObject object) { + if (voiceFallbackMethod != null) { + object.addProperty("voice_fallback_method", voiceFallbackMethod); + } else { + object.add("voice_fallback_method", JsonNull.INSTANCE); + } + } + + protected void writeVoiceFallbackUrl(final URI voiceFallbackUri, final HierarchicalStreamWriter writer) { + if (voiceFallbackUri != null) { + writer.startNode("VoiceFallbackUrl"); + writer.setValue(voiceFallbackUri.toString()); + writer.endNode(); + } + } + + protected void writeVoiceFallbackUrl(final URI voiceFallbackUri, final JsonObject object) { + if (voiceFallbackUri != null) { + object.addProperty("voice_fallback_url", voiceFallbackUri.toString()); + } else { + object.add("voice_fallback_url", JsonNull.INSTANCE); + } + } + + protected void writeVoiceMethod(final String voiceMethod, final HierarchicalStreamWriter writer) { + writer.startNode("VoiceMethod"); + if (voiceMethod != null) { + writer.setValue(voiceMethod); + } + writer.endNode(); + } + + protected void writeVoiceMethod(final String voiceMethod, final JsonObject object) { + if (voiceMethod != null) { + object.addProperty("voice_method", voiceMethod); + } else { + object.add("voice_method", JsonNull.INSTANCE); + } + } + + protected void writeVoiceUrl(final URI voiceUrl, final HierarchicalStreamWriter writer) { + if (voiceUrl != null) { + writer.startNode("VoiceUrl"); + writer.setValue(voiceUrl.toString()); + writer.endNode(); + } + } + + protected void writeVoiceUrl(final URI voiceUrl, final JsonObject object) { + if (voiceUrl != null) { + object.addProperty("voice_url", voiceUrl.toString()); + } else { + object.add("voice_url", JsonNull.INSTANCE); + } + } + + protected void writeReferUrl(final URI referUrl, final HierarchicalStreamWriter writer) { + if (referUrl != null) { + writer.startNode("ReferUrl"); + writer.setValue(referUrl.toString()); + writer.endNode(); + } + } + + protected void writeReferMethod(final String referMethod, final HierarchicalStreamWriter writer) { + writer.startNode("ReferMethod"); + if (referMethod != null) { + writer.setValue(referMethod); + } + writer.endNode(); + } + + protected void writeReferUrl(final URI referUrl, final JsonObject object) { + if (referUrl != null) { + object.addProperty("refer_url", referUrl.toString()); + } else { + object.add("refer_url", JsonNull.INSTANCE); + } + } + + protected void writeReferMethod(final String referMethod, final JsonObject object) { + if (referMethod != null) { + object.addProperty("refer_method", referMethod); + } else { + object.add("refer_method", JsonNull.INSTANCE); + } + } + + protected void writeCapabilities(final Boolean voiceCapable, final Boolean smsCapable, final Boolean mmsCapable, + final Boolean faxCapable, final HierarchicalStreamWriter writer) { + writer.startNode("Capabilities"); + writeVoiceCapability(voiceCapable, writer); + writeSmsCapability(smsCapable, writer); + writeMmsCapability(mmsCapable, writer); + writeFaxCapability(faxCapable, writer); + writer.endNode(); + } + + protected void writeCapabilities(final Boolean voiceCapable, final Boolean smsCapable, final Boolean mmsCapable, + final Boolean faxCapable, final JsonObject object) { + JsonObject capabilities = new JsonObject(); + writeVoiceCapability(voiceCapable, capabilities); + writeSmsCapability(smsCapable, capabilities); + writeMmsCapability(mmsCapable, capabilities); + writeFaxCapability(faxCapable, capabilities); + object.add("capabilities", capabilities); + } + + protected void writeVoiceCapability(final Boolean voiceCapable, final HierarchicalStreamWriter writer) { + writer.startNode("Voice"); + if (voiceCapable == null) { + writer.setValue(Boolean.FALSE.toString()); + } else { + writer.setValue(voiceCapable.toString()); + } + writer.endNode(); + } + + protected void writeVoiceCapability(final Boolean voiceCapable, final JsonObject object) { + if (voiceCapable != null) { + object.addProperty("voice_capable", voiceCapable); + } else { + object.addProperty("voice_capable", Boolean.FALSE); + } + } + + protected void writeSmsCapability(final Boolean smsCapable, final HierarchicalStreamWriter writer) { + writer.startNode("Sms"); + if (smsCapable == null) { + writer.setValue(Boolean.FALSE.toString()); + } else { + writer.setValue(smsCapable.toString()); + } + writer.endNode(); + } + + protected void writeSmsCapability(final Boolean smsCapable, final JsonObject object) { + if (smsCapable != null) { + object.addProperty("sms_capable", smsCapable); + } else { + object.addProperty("sms_capable", Boolean.FALSE); + } + } + + protected void writeMmsCapability(final Boolean mmsCapable, final HierarchicalStreamWriter writer) { + writer.startNode("Mms"); + if (mmsCapable == null) { + writer.setValue(Boolean.FALSE.toString()); + } else { + writer.setValue(mmsCapable.toString()); + } + writer.endNode(); + } + + protected void writeMmsCapability(final Boolean mmsCapable, final JsonObject object) { + if (mmsCapable != null) { + object.addProperty("mms_capable", mmsCapable); + } else { + object.addProperty("mms_capable", Boolean.FALSE); + } + } + + protected void writeFaxCapability(final Boolean faxCapable, final HierarchicalStreamWriter writer) { + writer.startNode("Fax"); + if (faxCapable == null) { + writer.setValue(Boolean.FALSE.toString()); + } else { + writer.setValue(faxCapable.toString()); + } + writer.endNode(); + } + + protected void writeFaxCapability(final Boolean faxCapable, final JsonObject object) { + if (faxCapable != null) { + object.addProperty("fax_capable", faxCapable); + } else { + object.addProperty("fax_capable", Boolean.FALSE); + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountConverter.java similarity index 81% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountConverter.java index b15fe0c035..af6789edb3 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountConverter.java @@ -17,22 +17,23 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; - -import java.lang.reflect.Type; +package org.restcomm.connect.http.converter; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; - import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.util.StringUtils; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Account; + +import javax.ws.rs.core.MediaType; +import java.lang.reflect.Type; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -40,12 +41,10 @@ @ThreadSafe public final class AccountConverter extends AbstractConverter implements JsonSerializer { private final String apiVersion; - private final String rootUri; public AccountConverter(final Configuration configuration) { super(configuration); this.apiVersion = configuration.getString("api-version"); - rootUri = StringUtils.addSuffixIfNotPresent(configuration.getString("root-uri"), "/"); } @SuppressWarnings("rawtypes") @@ -59,8 +58,13 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, final Account account = (Account) object; writer.startNode("Account"); writeSid(account.getSid(), writer); + writer.startNode("organization"); + writer.setValue(account.getOrganizationSid().toString()); + writer.endNode(); writeFriendlyName(account.getFriendlyName(), writer); + writeEmailAddress(account, writer); writeStatus(account.getStatus().toString(), writer); + writeRoleInfo(account.getRole(), writer); writeType(account.getType().toString(), writer); writeDateCreated(account.getDateCreated(), writer); writeDateUpdated(account.getDateUpdated(), writer); @@ -74,20 +78,35 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, public JsonElement serialize(final Account account, final Type type, final JsonSerializationContext context) { final JsonObject object = new JsonObject(); writeSid(account.getSid(), object); + object.addProperty("organization", account.getOrganizationSid().toString()); writeFriendlyName(account.getFriendlyName(), object); + writeEmailAddress(account, object); writeType(account.getType().toString(), object); writeStatus(account.getStatus().toString(), object); + writeRoleInfo(account.getRole(), object); writeDateCreated(account.getDateCreated(), object); writeDateUpdated(account.getDateUpdated(), object); writeAuthToken(account, object); - writeUri(account.getUri(), object); + writeUri(account, object); writeSubResourceUris(account, object); return object; } + protected void writeUri(final Account account, final JsonObject object) { + object.addProperty("uri", prefix(account, APPLICATION_JSON_TYPE)); + } + private String prefix(final Account account) { + return prefix(account, APPLICATION_XML_TYPE); + } + + private String prefix(final Account account, MediaType responseType) { final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(apiVersion).append("/Accounts/").append(account.getSid().toString()); + buffer.append("/").append(apiVersion).append("/Accounts"); + if(responseType == APPLICATION_JSON_TYPE) { + buffer.append(".json"); + } + buffer.append("/"+account.getSid().toString()); return buffer.toString(); } @@ -230,4 +249,27 @@ private void writeTranscriptions(final Account account, final HierarchicalStream private void writeTranscriptions(final Account account, final JsonObject object) { object.addProperty("transcriptions", prefix(account) + "/Transcriptions.json"); } + + private void writeEmailAddress(final Account account, final HierarchicalStreamWriter writer) { + writer.startNode("EmailAddress"); + writer.setValue(account.getEmailAddress()); + writer.endNode(); + writer.close(); + } + + private void writeEmailAddress(final Account account, final JsonObject object) { + object.addProperty("email_address", account.getEmailAddress()); + } + + private void writeRoleInfo(final String role, final HierarchicalStreamWriter writer) { + writer.startNode("Role"); + writer.setValue(role); + writer.endNode(); + writer.close(); + } + + private void writeRoleInfo(final String role, final JsonObject object) { + object.addProperty("role", role); + } + } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountListConverter.java similarity index 88% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountListConverter.java index 01c0b007d7..75fa3d28ee 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AccountListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AccountListConverter.java @@ -17,12 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.apache.http.annotation.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Account; -import org.mobicents.servlet.restcomm.entities.AccountList; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.AccountList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -30,7 +29,6 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -@ThreadSafe public final class AccountListConverter extends AbstractConverter { public AccountListConverter(final Configuration configuration) { super(configuration); diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementConverter.java similarity index 94% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementConverter.java index e08bde3037..23bc5431d3 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementConverter.java @@ -1,10 +1,10 @@ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Announcement; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Announcement; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementListConverter.java similarity index 79% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementListConverter.java index e41c96ee64..1b238dd278 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AnnouncementListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AnnouncementListConverter.java @@ -1,9 +1,9 @@ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Announcement; -import org.mobicents.servlet.restcomm.entities.AnnouncementList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Announcement; +import org.restcomm.connect.dao.entities.AnnouncementList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationConverter.java new file mode 100644 index 0000000000..12e38296f2 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationConverter.java @@ -0,0 +1,130 @@ +/* + * 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.converter; + +import java.lang.reflect.Type; +import java.net.URI; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Application; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.restcomm.connect.dao.entities.ApplicationNumberSummary; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class ApplicationConverter extends AbstractConverter implements JsonSerializer { + public ApplicationConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Application.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Application application = (Application) object; + writer.startNode("Application"); + writeSid(application.getSid(), writer); + writeDateCreated(application.getDateCreated(), writer); + writeDateUpdated(application.getDateUpdated(), writer); + writeFriendlyName(application.getFriendlyName(), writer); + writeAccountSid(application.getAccountSid(), writer); + writeApiVersion(application.getApiVersion(), writer); + writeVoiceCallerIdLookup(application.hasVoiceCallerIdLookup(), writer); + writeUri(application.getUri(), writer); + writeRcmlUrl(application.getRcmlUrl(), writer); + writeKind(application.getKind(), writer); + writeNumbers(application.getNumbers(), writer, context); + writer.endNode(); + } + + @Override + public JsonElement serialize(final Application application, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(application.getSid(), object); + writeDateCreated(application.getDateCreated(), object); + writeDateUpdated(application.getDateUpdated(), object); + writeFriendlyName(application.getFriendlyName(), object); + writeAccountSid(application.getAccountSid(), object); + writeApiVersion(application.getApiVersion(), object); + writeVoiceCallerIdLookup(application.hasVoiceCallerIdLookup(), object); + writeUri(application.getUri(), object); + writeRcmlUrl(application.getRcmlUrl(), object); + writeKind(application.getKind(), object); + object.add("numbers",context.serialize(application.getNumbers())); + return object; + } + + private void writeRcmlUrl(final URI rcmlUrl, final HierarchicalStreamWriter writer) { + if (rcmlUrl != null) { + writer.startNode("RcmlUrl"); + writer.setValue(rcmlUrl.toString()); + writer.endNode(); + } + } + + private void writeRcmlUrl(final URI rcmlUrl, final JsonObject object) { + if (rcmlUrl != null) { + object.addProperty("rcml_url", rcmlUrl.toString()); + } else { + object.add("rcml_url", JsonNull.INSTANCE); + } + } + + private void writeKind(final Application.Kind kind, final HierarchicalStreamWriter writer) { + if (kind != null) { + writer.startNode("Kind"); + writer.setValue(kind.toString()); + writer.endNode(); + } + } + + private void writeKind(final Application.Kind kind, final JsonObject object) { + if (kind != null) { + object.addProperty("kind", kind.toString()); + } else { + object.add("kind", JsonNull.INSTANCE); + } + } + + private void writeNumbers(final List numbers, final HierarchicalStreamWriter writer, final MarshallingContext context) { + if (numbers != null) { + writer.startNode("Numbers"); + context.convertAnother(numbers); + writer.endNode(); + } + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationListConverter.java index 6afe2d118e..b57ec0ea26 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ApplicationListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationListConverter.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Application; -import org.mobicents.servlet.restcomm.entities.ApplicationList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.dao.entities.ApplicationList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationNumberSummaryConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationNumberSummaryConverter.java new file mode 100644 index 0000000000..6f91f7f08f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ApplicationNumberSummaryConverter.java @@ -0,0 +1,78 @@ +/* + * 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.converter; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.restcomm.connect.dao.entities.ApplicationNumberSummary; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class ApplicationNumberSummaryConverter implements Converter { + @Override + public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) { + ApplicationNumberSummary number = (ApplicationNumberSummary) o; + if (number.getSid() != null ) { + writer.startNode("Sid"); + writer.setValue(number.getSid()); + writer.endNode(); + } + if (number.getFriendlyName() != null) { + writer.startNode("FriendlyName"); + writer.setValue(number.getFriendlyName()); + writer.endNode(); + } + if (number.getPhoneNumber() != null) { + writer.startNode("PhoneNumber"); + writer.setValue(number.getPhoneNumber()); + writer.endNode(); + } + if (number.getVoiceApplicationSid() != null) { + writer.startNode("VoiceApplicationSid"); + writer.setValue(number.getVoiceApplicationSid()); + writer.endNode(); + } + if (number.getSmsApplicationSid() != null) { + writer.startNode("SmsApplicationSid"); + writer.setValue(number.getSmsApplicationSid()); + writer.endNode(); + } + if (number.getUssdApplicationSid() != null) { + writer.startNode("UssdApplicationSid"); + writer.setValue(number.getUssdApplicationSid()); + writer.endNode(); + } + } + + @Override + public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) { + return null; + } + + @Override + public boolean canConvert(Class aClass) { + return ApplicationNumberSummary.class.equals(aClass); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesConverter.java similarity index 97% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesConverter.java index d532ff5c27..78b947fb84 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesConverter.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesList.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesList.java similarity index 96% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesList.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesList.java index c1163d698b..d76a86dbb8 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailableCountriesList.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailableCountriesList.java @@ -17,7 +17,7 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.util.List; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberConverter.java similarity index 97% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberConverter.java index 551d69dbb5..a99cd3aa5c 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberConverter.java @@ -17,10 +17,10 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumber; +import org.restcomm.connect.dao.entities.AvailablePhoneNumber; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberListConverter.java similarity index 90% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberListConverter.java index 1d1a2d2dd8..32b7f5b5ec 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/AvailablePhoneNumberListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/AvailablePhoneNumberListConverter.java @@ -17,11 +17,11 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumber; -import org.mobicents.servlet.restcomm.entities.AvailablePhoneNumberList; +import org.restcomm.connect.dao.entities.AvailablePhoneNumber; +import org.restcomm.connect.dao.entities.AvailablePhoneNumberList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordConverter.java similarity index 86% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordConverter.java index 135412456e..1c88bbcfe3 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordConverter.java @@ -17,25 +17,21 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; - import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -import java.lang.reflect.Type; - import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.util.StringUtils; +import java.lang.reflect.Type; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -43,12 +39,10 @@ @ThreadSafe public final class CallDetailRecordConverter extends AbstractConverter implements JsonSerializer { private final String apiVersion; - private final String rootUri; public CallDetailRecordConverter(final Configuration configuration) { super(configuration); apiVersion = configuration.getString("api-version"); - rootUri = StringUtils.addSuffixIfNotPresent(configuration.getString("root-uri"), "/"); } @SuppressWarnings("rawtypes") @@ -62,6 +56,7 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, final CallDetailRecord cdr = (CallDetailRecord) object; writer.startNode("Call"); writeSid(cdr.getSid(), writer); + writeInstanceId(cdr.getInstanceId(), writer); writeDateCreated(cdr.getDateCreated(), writer); writeDateUpdated(cdr.getDateUpdated(), writer); writeParentCallSid(cdr.getParentCallSid(), writer); @@ -82,12 +77,13 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, writeCallerName(cdr.getCallerName(), writer); writeUri(cdr.getUri(), writer); writeSubResources(cdr, writer); + writeRingDuration(cdr.getRingDuration(), writer); writer.endNode(); } private String prefix(final CallDetailRecord cdr) { final StringBuilder buffer = new StringBuilder(); - buffer.append(rootUri).append(apiVersion).append("/Accounts/"); + buffer.append("/").append(apiVersion).append("/Accounts/"); buffer.append(cdr.getAccountSid().toString()).append("/Calls/"); buffer.append(cdr.getSid()); return buffer.toString(); @@ -97,6 +93,7 @@ private String prefix(final CallDetailRecord cdr) { public JsonElement serialize(final CallDetailRecord cdr, Type type, final JsonSerializationContext context) { final JsonObject object = new JsonObject(); writeSid(cdr.getSid(), object); + writeInstanceId(cdr.getInstanceId(), object); writeDateCreated(cdr.getDateCreated(), object); writeDateUpdated(cdr.getDateUpdated(), object); writeParentCallSid(cdr.getParentCallSid(), object); @@ -115,6 +112,7 @@ public JsonElement serialize(final CallDetailRecord cdr, Type type, final JsonSe writeForwardedFrom(cdr.getForwardedFrom(), object); writeCallerName(cdr.getCallerName(), object); writeUri(cdr.getUri(), object); + writeRingDuration(cdr.getRingDuration(), object); writeSubResources(cdr, object); return object; } @@ -165,6 +163,18 @@ private void writeDuration(final Integer duration, final JsonObject object) { object.addProperty("duration", duration); } + private void writeRingDuration(final Integer ringDuration, final HierarchicalStreamWriter writer) { + writer.startNode("Ring_duration"); + if (ringDuration != null) { + writer.setValue(ringDuration.toString()); + } + writer.endNode(); + } + + private void writeRingDuration(final Integer ringDuration, final JsonObject object) { + object.addProperty("ring_duration", ringDuration); + } + private void writeForwardedFrom(final String forwardedFrom, final HierarchicalStreamWriter writer) { writer.startNode("ForwardedFrom"); if (forwardedFrom != null) { @@ -240,7 +250,7 @@ private void writeNotifications(final CallDetailRecord cdr, final HierarchicalSt } private void writeNotifications(final CallDetailRecord cdr, final JsonObject object) { - object.addProperty("notifications", prefix(cdr) + "/Notifications"); + object.addProperty("notifications", prefix(cdr) + "/Notifications.json"); } private void writeRecordings(final CallDetailRecord cdr, final HierarchicalStreamWriter writer) { @@ -250,7 +260,7 @@ private void writeRecordings(final CallDetailRecord cdr, final HierarchicalStrea } private void writeRecordings(final CallDetailRecord cdr, final JsonObject object) { - object.addProperty("recordings", prefix(cdr) + "/Recordings"); + object.addProperty("recordings", prefix(cdr) + "/Recordings.json"); } private void writeSubResources(final CallDetailRecord cdr, final HierarchicalStreamWriter writer) { @@ -266,4 +276,17 @@ private void writeSubResources(final CallDetailRecord cdr, final JsonObject obje writeRecordings(cdr, other); object.add("subresource_uris", other); } + + private void writeInstanceId(final String instanceId, final HierarchicalStreamWriter writer) { + if (instanceId != null && !instanceId.isEmpty()) { + writer.startNode("InstanceId"); + writer.setValue(instanceId); + writer.endNode(); + } + } + + private void writeInstanceId(final String instanceId, final JsonObject object) { + if (instanceId != null && !instanceId.isEmpty()) + object.addProperty("InstanceId", instanceId); + } } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordListConverter.java similarity index 82% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordListConverter.java index ab00bbe6ac..42929b9920 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/CallDetailRecordListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallDetailRecordListConverter.java @@ -17,14 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.CallDetailRecordList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.CallDetailRecordList; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -70,7 +70,7 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, writer.addAttribute("firstpageuri", getFirstPageUri()); writer.addAttribute("previouspageuri", getPreviousPageUri()); writer.addAttribute("nextpageuri", getNextPageUri(list)); - writer.addAttribute("lastpageuri=", getLastPageUri()); + writer.addAttribute("lastpageuri", getLastPageUri()); for (final CallDetailRecord cdr : list.getCallDetailRecords()) { context.convertAnother(cdr); @@ -90,17 +90,20 @@ public JsonObject serialize(CallDetailRecordList cdrList, Type type, JsonSeriali array.add(context.serialize(cdr)); } - result.addProperty("page", page); - result.addProperty("num_pages", getTotalPages()); - result.addProperty("page_size", pageSize); - result.addProperty("total", total); - result.addProperty("start", getFirstIndex()); - result.addProperty("end", getLastIndex(cdrList)); - result.addProperty("uri", pathUri); - result.addProperty("first_page_uri", getFirstPageUri()); - result.addProperty("previous_page_uri", getPreviousPageUri()); - result.addProperty("next_page_uri", getNextPageUri(cdrList)); - result.addProperty("last_page_uri", getLastPageUri()); + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(cdrList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(cdrList)); + result.addProperty("last_page_uri", getLastPageUri()); + } + result.add("calls", array); return result; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallinfoConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallinfoConverter.java new file mode 100644 index 0000000000..6b94df2d6c --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/CallinfoConverter.java @@ -0,0 +1,169 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http.converter; + +import java.lang.reflect.Type; + +import javax.servlet.sip.URI; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.commons.util.StringUtils; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author gvagenas + * + */ +public class CallinfoConverter extends AbstractConverter implements JsonSerializer{ + private final String apiVersion; + private final String rootUri; + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return CallInfo.class.equals(klass); + } + + /** + * @param configuration + */ + public CallinfoConverter(Configuration configuration) { + super(configuration); + apiVersion = configuration.getString("api-version"); + rootUri = StringUtils.addSuffixIfNotPresent(configuration.getString("root-uri"), "/"); + } + + @Override + public JsonElement serialize(CallInfo callInfo, Type typeOfSrc, JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(callInfo.sid(), object); + writeState(callInfo.state().name(), object); + if (callInfo.type() != null) + writeType(callInfo.type().name(), object); + writeDirection(callInfo.direction(), object); + writeDateCreated(callInfo.dateCreated(), object); + writeForwardedFrom(callInfo.forwardedFrom(), object); + writeCallerName(callInfo.fromName(), object); + writeFrom(callInfo.from(), object); + writeTo(callInfo.to(), object); + if (callInfo.invite() != null) { + writeInviteUri(callInfo.invite().getRequestURI(), object); + } + if (callInfo.lastResponse() != null) + writeLastResponseUri(callInfo.lastResponse().getStatus(), object); + return object; + } + + @Override + public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + final CallInfo callInfo = (CallInfo) object; + writer.startNode("CallInfo"); + writeSid(callInfo.sid(), writer); + writeState(callInfo.state().name(), writer); + if (callInfo.type() != null) + writeType(callInfo.type().name(), writer); + writeDirection(callInfo.direction(), writer); + writeDateCreated(callInfo.dateCreated(), writer); + writeForwardedFrom(callInfo.forwardedFrom(), writer); + writeCallerName(callInfo.fromName(), writer); + writeFrom(callInfo.from(), writer); + writeTo(callInfo.to(), writer); + writeInviteUri(callInfo.invite().getRequestURI(), writer); + if (callInfo.lastResponse() != null) + writeLastResponseUri(callInfo.lastResponse().getStatus(), writer); + writer.endNode(); + } + + private void writeState(final String state, final HierarchicalStreamWriter writer) { + writer.startNode("State"); + writer.setValue(state); + writer.endNode(); + } + + private void writeState(final String state, final JsonObject object) { + object.addProperty("State", state); + } + + private void writeDirection(final String direction, final HierarchicalStreamWriter writer) { + writer.startNode("Direction"); + writer.setValue(direction); + writer.endNode(); + } + + private void writeDirection(final String direction, final JsonObject object) { + object.addProperty("direction", direction); + } + + private void writeForwardedFrom(final String forwardedFrom, final HierarchicalStreamWriter writer) { + writer.startNode("ForwardedFrom"); + if (forwardedFrom != null) { + writer.setValue(forwardedFrom); + } + writer.endNode(); + } + + private void writeForwardedFrom(final String forwardedFrom, final JsonObject object) { + object.addProperty("ForwardedFrom", forwardedFrom); + } + + private void writeCallerName(final String callerName, final HierarchicalStreamWriter writer) { + writer.startNode("CallerName"); + if (callerName != null) { + writer.setValue(callerName); + } + writer.endNode(); + } + + private void writeCallerName(final String callerName, final JsonObject object) { + object.addProperty("CallerName", callerName); + } + + private void writeInviteUri(final URI requestUri, final HierarchicalStreamWriter writer) { + writer.startNode("Initial Invite"); + if (requestUri != null) { + writer.setValue(requestUri.toString()); + } + writer.endNode(); + } + + private void writeInviteUri(final URI requestUri, final JsonObject object) { + object.addProperty("Initial Invite", requestUri.toString()); + } + + private void writeLastResponseUri(final int responseCode, final HierarchicalStreamWriter writer) { + writer.startNode("Last Response"); + if (responseCode > -1) { + writer.setValue(String.valueOf(responseCode)); + } + writer.endNode(); + } + + private void writeLastResponseUri(final int responseCode, final JsonObject object) { + object.addProperty("Last Response", responseCode); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientConverter.java similarity index 93% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientConverter.java index b73c07ce6e..52b296a843 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientConverter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Client; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Client; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -66,6 +66,7 @@ public void marshal(final Object object, final HierarchicalStreamWriter writer, writeVoiceFallbackMethod(client.getVoiceFallbackMethod(), writer); writeVoiceApplicationSid(client.getVoiceApplicationSid(), writer); writeUri(client.getUri(), writer); + writePushClientIdentity(client.getPushClientIdentity(), writer); writer.endNode(); } @@ -87,6 +88,7 @@ public JsonElement serialize(final Client client, final Type type, final JsonSer writeVoiceFallbackMethod(client.getVoiceFallbackMethod(), object); writeVoiceApplicationSid(client.getVoiceApplicationSid(), object); writeUri(client.getUri(), object); + writePushClientIdentity(client.getPushClientIdentity(), object); return object; } diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientListConverter.java index 827e44b6ea..e8579402bd 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ClientListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ClientListConverter.java @@ -17,15 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Client; -import org.mobicents.servlet.restcomm.entities.ClientList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Client; +import org.restcomm.connect.dao.entities.ClientList; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordConverter.java new file mode 100644 index 0000000000..fc6dd94c28 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordConverter.java @@ -0,0 +1,112 @@ +/* + * 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.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; + +import java.lang.reflect.Type; + +/** + * @author maria + */ +@ThreadSafe +public final class ConferenceDetailRecordConverter extends AbstractConverter implements JsonSerializer { + private final String apiVersion; + + public ConferenceDetailRecordConverter(final Configuration configuration) { + super(configuration); + apiVersion = configuration.getString("api-version"); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return ConferenceDetailRecord.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final ConferenceDetailRecord cdr = (ConferenceDetailRecord) object; + writer.startNode("Conference"); + writeSid(cdr.getSid(), writer); + writeDateCreated(cdr.getDateCreated(), writer); + writeDateUpdated(cdr.getDateUpdated(), writer); + writeAccountSid(cdr.getAccountSid(), writer); + writeStatus(cdr.getStatus(), writer); + writeApiVersion(cdr.getApiVersion(), writer); + writeFriendlyName(cdr.getFriendlyName(), writer); + writeUri(cdr.getUri(), writer); + writeSubResources(cdr, writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final ConferenceDetailRecord cdr, Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(cdr.getSid(), object); + writeDateCreated(cdr.getDateCreated(), object); + writeDateUpdated(cdr.getDateUpdated(), object); + writeAccountSid(cdr.getAccountSid(), object); + writeStatus(cdr.getStatus(), object); + writeApiVersion(cdr.getApiVersion(), object); + writeFriendlyName(cdr.getFriendlyName(), object); + writeUri(cdr.getUri(), object); + writeSubResources(cdr, object); + return object; + } + + private void writeSubResources(final ConferenceDetailRecord cdr, final HierarchicalStreamWriter writer) { + writer.startNode("SubresourceUris"); + writeParticipants(cdr, writer); + writer.endNode(); + } + + private void writeSubResources(final ConferenceDetailRecord cdr, final JsonObject object) { + final JsonObject other = new JsonObject(); + writeParticipants(cdr, other); + object.add("subresource_uris", other); + } + + private void writeParticipants(final ConferenceDetailRecord cdr, final HierarchicalStreamWriter writer) { + writer.startNode("Participants"); + writer.setValue(prefix(cdr) + "/Participants"); + writer.endNode(); + } + + private void writeParticipants(final ConferenceDetailRecord cdr, final JsonObject object) { + object.addProperty("participants", prefix(cdr) + "/Participants.json"); + } + + private String prefix(final ConferenceDetailRecord cdr) { + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(apiVersion).append("/Accounts/"); + buffer.append(cdr.getAccountSid().toString()).append("/Conferences/"); + buffer.append(cdr.getSid()); + return buffer.toString(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordListConverter.java new file mode 100644 index 0000000000..f42ecb9063 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceDetailRecordListConverter.java @@ -0,0 +1,151 @@ +/* + * 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.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.dao.entities.ConferenceDetailRecordList; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author maria + */ +@ThreadSafe +public final class ConferenceDetailRecordListConverter extends AbstractConverter implements JsonSerializer { + + Integer page, pageSize, total; + String pathUri; + + public ConferenceDetailRecordListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return ConferenceDetailRecordList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final ConferenceDetailRecordList list = (ConferenceDetailRecordList) object; + + writer.startNode("Conferences"); + writer.addAttribute("page", String.valueOf(page)); + writer.addAttribute("numpages", String.valueOf(getTotalPages())); + writer.addAttribute("pagesize", String.valueOf(pageSize)); + writer.addAttribute("total", String.valueOf(getTotalPages())); + writer.addAttribute("start", getFirstIndex()); + writer.addAttribute("end", getLastIndex(list)); + writer.addAttribute("uri", pathUri); + writer.addAttribute("firstpageuri", getFirstPageUri()); + writer.addAttribute("previouspageuri", getPreviousPageUri()); + writer.addAttribute("nextpageuri", getNextPageUri(list)); + writer.addAttribute("lastpageuri", getLastPageUri()); + + for (final ConferenceDetailRecord cdr : list.getConferenceDetailRecords()) { + context.convertAnother(cdr); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(ConferenceDetailRecordList cdrList, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (ConferenceDetailRecord cdr : cdrList.getConferenceDetailRecords()) { + array.add(context.serialize(cdr)); + } + + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(cdrList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(cdrList)); + result.addProperty("last_page_uri", getLastPageUri()); + result.add("conferences", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(ConferenceDetailRecordList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getConferenceDetailRecords().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(ConferenceDetailRecordList list) { + String lastSid = (page == getTotalPages()) ? "null" : list.getConferenceDetailRecords().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceParticipantConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceParticipantConverter.java new file mode 100644 index 0000000000..4fe5dea19a --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ConferenceParticipantConverter.java @@ -0,0 +1,155 @@ +/* + * 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.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.CallDetailRecord; + +import java.lang.reflect.Type; + +/** + * @author maria-farooq@live.com.com (Maria Farooq) + */ +@ThreadSafe +public final class ConferenceParticipantConverter extends AbstractConverter implements JsonSerializer { + private final String apiVersion; + + public ConferenceParticipantConverter(final Configuration configuration) { + super(configuration); + apiVersion = configuration.getString("api-version"); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return CallDetailRecord.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final CallDetailRecord cdr = (CallDetailRecord) object; + writer.startNode("Call"); + writeSid(cdr.getSid(), writer); + writeConferenceSid(cdr.getConferenceSid(), writer); + writeDateCreated(cdr.getDateCreated(), writer); + writeDateUpdated(cdr.getDateUpdated(), writer); + writeAccountSid(cdr.getAccountSid(), writer); + writeMuted(cdr.isMuted(), writer); + writeHold(cdr.isOnHold(), writer); + writeStartConferenceOnEnter(cdr.isStartConferenceOnEnter(), writer); + writeEndConferenceOnEnter(cdr.isEndConferenceOnExit(), writer); + writeUri(cdr.getUri(), writer); + writer.endNode(); + } + + private String prefix(final CallDetailRecord cdr) { + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(apiVersion).append("/Accounts/"); + buffer.append(cdr.getAccountSid().toString()).append("/Calls/"); + buffer.append(cdr.getSid()); + return buffer.toString(); + } + + @Override + public JsonElement serialize(final CallDetailRecord cdr, Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(cdr.getSid(), object); + writeConferenceSid(cdr.getParentCallSid(), object); + writeDateCreated(cdr.getDateCreated(), object); + writeDateUpdated(cdr.getDateUpdated(), object); + writeAccountSid(cdr.getAccountSid(), object); + writeMuted(cdr.isMuted(), object); + writeHold(cdr.isOnHold(), object); + writeStartConferenceOnEnter(cdr.isStartConferenceOnEnter(), object); + writeEndConferenceOnEnter(cdr.isEndConferenceOnExit(), object); + writeUri(cdr.getUri(), object); + return object; + } + + private void writeMuted(final Boolean muted, final HierarchicalStreamWriter writer) { + writer.startNode("Muted"); + if (muted != null) { + writer.setValue(muted.toString()); + } + writer.endNode(); + } + + private void writeMuted(final Boolean muted, final JsonObject object) { + object.addProperty("muted", muted); + } + + private void writeHold(final Boolean hold, final HierarchicalStreamWriter writer) { + writer.startNode("Hold"); + if (hold != null) { + writer.setValue(hold.toString()); + } + writer.endNode(); + } + + private void writeHold(final Boolean hold, final JsonObject object) { + object.addProperty("hold", hold); + } + + private void writeStartConferenceOnEnter(final Boolean startConferenceOnEnter, final HierarchicalStreamWriter writer) { + writer.startNode("StartConferenceOnEnter"); + if (startConferenceOnEnter != null) { + writer.setValue(startConferenceOnEnter.toString()); + } + writer.endNode(); + } + + private void writeStartConferenceOnEnter(final Boolean startConferenceOnEnter, final JsonObject object) { + object.addProperty("start_conference_on_enter", startConferenceOnEnter); + } + + private void writeEndConferenceOnEnter(final Boolean endConferenceOnEnter, final HierarchicalStreamWriter writer) { + writer.startNode("EndConferenceOnEnter"); + if (endConferenceOnEnter != null) { + writer.setValue(endConferenceOnEnter.toString()); + } + writer.endNode(); + } + + private void writeEndConferenceOnEnter(final Boolean endConferenceOnEnter, final JsonObject object) { + object.addProperty("end_conference_on_enter", endConferenceOnEnter); + } + + private void writeConferenceSid(final Sid sid, final HierarchicalStreamWriter writer) { + writer.startNode("ConferenceSid"); + if (sid != null) { + writer.setValue(sid.toString()); + } + writer.endNode(); + } + + private void writeConferenceSid(final Sid sid, final JsonObject object) { + if (sid != null) { + object.addProperty("conference_sid", sid.toString()); + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/EmailMessageConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/EmailMessageConverter.java new file mode 100644 index 0000000000..48803a3b2a --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/EmailMessageConverter.java @@ -0,0 +1,115 @@ + +/* + * 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.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.email.api.Mail; +import org.restcomm.connect.commons.dao.Sid; + + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author eleftherios.banos@telestax.com (Lefteis Banos) + */ +public class EmailMessageConverter extends AbstractConverter implements JsonSerializer { + public EmailMessageConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Mail.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Mail mailMessage = (Mail) object; + writer.startNode("EmailMessage"); + writeDateSent(mailMessage.dateSent(), writer); + writeAccountSid(new Sid(mailMessage.accountSid()), writer); + writeFrom(mailMessage.from(), writer); + writeTo(mailMessage.to(), writer); + writeBody(mailMessage.body(), writer); + writeSubject(mailMessage.subject().toString(), writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final Mail mailMessage, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeDateSent(mailMessage.dateSent(), object); + writeAccountSid(new Sid(mailMessage.accountSid()), object); + writeFrom(mailMessage.from(), object); + writeTo(mailMessage.to(), object); + writeBody(mailMessage.body(), object); + writeSubject(mailMessage.subject().toString(), object); + return object; + } + + private void writeBody(final String body, final HierarchicalStreamWriter writer) { + writer.startNode("Body"); + if (body != null) { + writer.setValue(body); + } + writer.endNode(); + } + + private void writeBody(final String body, final JsonObject object) { + if (body != null) { + object.addProperty("body", body); + } else { + object.add("body", JsonNull.INSTANCE); + } + } + + private void writeDateSent(final DateTime dateSent, final HierarchicalStreamWriter writer) { + writer.startNode("DateSent"); + if (dateSent != null) { + writer.setValue(dateSent.toString()); + } + writer.endNode(); + } + + private void writeDateSent(final DateTime dateSent, final JsonObject object) { + object.addProperty("date_sent", dateSent != null ? dateSent.toString() : null); + } + + private void writeSubject(final String subject, final HierarchicalStreamWriter writer) { + writer.startNode("Subject"); + writer.setValue(subject); + writer.endNode(); + } + + private void writeSubject(final String subject, final JsonObject object) { + object.addProperty("subject", subject); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ExtensionConfigurationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ExtensionConfigurationConverter.java new file mode 100644 index 0000000000..ad8ae17ec9 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ExtensionConfigurationConverter.java @@ -0,0 +1,84 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.util.StringUtils; +import org.restcomm.connect.extension.api.ExtensionConfiguration; + +import java.lang.reflect.Type; + +/** + * @author gvagenas@gmail.com + */ +@ThreadSafe +public final class ExtensionConfigurationConverter extends AbstractConverter implements JsonSerializer { + private final String apiVersion; + private final String rootUri; + + public ExtensionConfigurationConverter(final Configuration configuration) { + super(configuration); + this.apiVersion = configuration.getString("api-version"); + rootUri = StringUtils.addSuffixIfNotPresent(configuration.getString("root-uri"), "/"); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return ExtensionConfiguration.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final ExtensionConfiguration extensionConfiguration = (ExtensionConfiguration) object; + writer.startNode("ExtensionConfiguration"); + writeSid(extensionConfiguration.getSid(),writer); + writer.startNode("Extension"); + writer.setValue(extensionConfiguration.getExtensionName()); + writer.endNode(); + writer.startNode("Configuration"); + writer.setValue(extensionConfiguration.getConfigurationData().toString()); + writer.endNode(); + writer.startNode("Configuration Type"); + writer.setValue(extensionConfiguration.getConfigurationType().name()); + writer.endNode(); + writeDateCreated(extensionConfiguration.getDateCreated(),writer); + writeDateCreated(extensionConfiguration.getDateUpdated(), writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final ExtensionConfiguration extensionConfiguration, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(extensionConfiguration.getSid(), object); + object.addProperty("extension", extensionConfiguration.getExtensionName()); + object.addProperty("configuration", extensionConfiguration.getConfigurationData().toString()); + object.addProperty("configuration type", extensionConfiguration.getConfigurationType().name()); + writeDateCreated(extensionConfiguration.getDateCreated(), object); + writeDateUpdated(extensionConfiguration.getDateUpdated(), object); + return object; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayConverter.java similarity index 95% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayConverter.java index cd20a8683b..c498bf4671 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayConverter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Gateway; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Gateway; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayListConverter.java index bdfff5559e..7baee01ba5 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/GatewayListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GatewayListConverter.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Gateway; -import org.mobicents.servlet.restcomm.entities.GatewayList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.dao.entities.GatewayList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationConverter.java new file mode 100644 index 0000000000..3e56088e3b --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationConverter.java @@ -0,0 +1,532 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http.converter; + +import java.lang.reflect.Type; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.restcomm.connect.dao.entities.Geolocation; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * @author Fernando Mendioroz + * + */ +public class GeolocationConverter extends AbstractConverter implements JsonSerializer { + + public GeolocationConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Geolocation.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + + final Geolocation geolocation = (Geolocation) object; + writer.startNode("Geolocation"); + writeSid(geolocation.getSid(), writer); + writeDateCreated(geolocation.getDateCreated(), writer); + writeDateUpdated(geolocation.getDateUpdated(), writer); + writeDateExecuted(geolocation.getDateExecuted(), writer); + writeAccountSid(geolocation.getAccountSid(), writer); + writeSource(geolocation.getSource(), writer); + writeDeviceIdentifier(geolocation.getDeviceIdentifier(), writer); + writeGeolocationType(geolocation.getGeolocationType(), writer); + writeResponseStatus(geolocation.getResponseStatus(), writer); + writeGeolocationData(geolocation, writer); /*** GeolocationData XML ***/ + writeGeolocationPositioningType(geolocation.getGeolocationPositioningType(), writer); + writeLastGeolocationResponse(geolocation.getLastGeolocationResponse(), writer); + writeCause(geolocation.getCause(), writer); + writeApiVersion(geolocation.getApiVersion(), writer); + writeUri(geolocation.getUri(), writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final Geolocation geolocation, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(geolocation.getSid(), object); + writeDateCreated(geolocation.getDateCreated(), object); + writeDateUpdated(geolocation.getDateUpdated(), object); + writeDateExecuted(geolocation.getDateExecuted(), object); + writeAccountSid(geolocation.getAccountSid(), object); + writeSource(geolocation.getSource(), object); + writeDeviceIdentifier(geolocation.getDeviceIdentifier(), object); + writeGeolocationType(geolocation.getGeolocationType(), object); + writeResponseStatus(geolocation.getResponseStatus(), object); + writeGeolocationData(geolocation, object); /*** GeolocationData JSON ***/ + writeGeolocationPositioningType(geolocation.getGeolocationPositioningType(), object); + writeLastGeolocationResponse(geolocation.getLastGeolocationResponse(), object); + writeCause(geolocation.getCause(), object); + writeApiVersion(geolocation.getApiVersion(), object); + writeUri(geolocation.getUri(), object); + return object; + } + + protected void writeDateExecuted(final DateTime dateExecuted, final HierarchicalStreamWriter writer) { + writer.startNode("DateExecuted"); + writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateExecuted.toDate())); + writer.endNode(); + } + + protected void writeDateExecuted(final DateTime dateExecuted, final JsonObject object) { + object.addProperty("date_executed", + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(dateExecuted.toDate())); + } + + protected void writeSource(final String source, final HierarchicalStreamWriter writer) { + if (source != null) { + writer.startNode("Source"); + writer.setValue(source); + writer.endNode(); + } + } + + protected void writeSource(final String source, final JsonObject object) { + if (source != null) { + object.addProperty("source", source); + } else { + object.add("source", JsonNull.INSTANCE); + } + } + + protected void writeDeviceIdentifier(final String deviceIdentifier, final HierarchicalStreamWriter writer) { + if (deviceIdentifier != null) { + writer.startNode("DeviceIdentifier"); + writer.setValue(deviceIdentifier); + writer.endNode(); + } + } + + protected void writeDeviceIdentifier(final String deviceIdentifier, final JsonObject object) { + if (deviceIdentifier != null) { + object.addProperty("device_identifier", deviceIdentifier); + } else { + object.add("device_identifier", JsonNull.INSTANCE); + } + } + + protected void writeGeolocationType(final Geolocation.GeolocationType geolocationType, + final HierarchicalStreamWriter writer) { + if (geolocationType != null) { + writer.startNode("GeolocationType"); + writer.setValue(geolocationType.toString()); + writer.endNode(); + } + } + + protected void writeGeolocationType(final Geolocation.GeolocationType geolocationType, final JsonObject object) { + if (geolocationType != null) { + object.addProperty("geolocation_type", geolocationType.toString()); + } else { + object.add("geolocation_type", JsonNull.INSTANCE); + } + } + + protected void writeResponseStatus(final String responseStatus, final HierarchicalStreamWriter writer) { + if (responseStatus != null) { + writer.startNode("ResponseStatus"); + writer.setValue(responseStatus); + writer.endNode(); + } + } + + protected void writeResponseStatus(final String responseStatus, final JsonObject object) { + if (responseStatus != null) { + object.addProperty("response_status", responseStatus); + } else { + object.add("response_status", JsonNull.INSTANCE); + } + } + + protected void writeGeolocationData(Geolocation geolocation, final HierarchicalStreamWriter writer) { + writer.startNode("GeolocationData"); + if (geolocation != null) { + writeCellId(geolocation.getCellId(), writer); + writeLocationAreaCode(geolocation.getLocationAreaCode(), writer); + writeMobileCountryCode(geolocation.getMobileCountryCode(), writer); + writeMobileNetworkCode(geolocation.getMobileNetworkCode(), writer); + writeNetworkEntityAddress(geolocation.getNetworkEntityAddress(), writer); + writeAgeOfLocationInfo(geolocation.getAgeOfLocationInfo(), writer); + writeDeviceLatitude(geolocation.getDeviceLatitude(), writer); + writeDeviceLongitude(geolocation.getDeviceLongitude(), writer); + writeAccuracy(geolocation.getAccuracy(), writer); + writeInternetAddress(geolocation.getInternetAddress(), writer); + writePhysicalAddress(geolocation.getPhysicalAddress(), writer); + writeFormattedAddress(geolocation.getFormattedAddress(), writer); + writeLocationTimestamp(geolocation.getLocationTimestamp(), writer); + writeEventGeofenceLatitude(geolocation.getEventGeofenceLatitude(), writer); + writeEventGeofenceLongitude(geolocation.getEventGeofenceLongitude(), writer); + writeRadius(geolocation.getRadius(), writer); + } + writer.endNode(); + } + + protected void writeGeolocationData(Geolocation geolocation, final JsonObject object) { + if (geolocation != null) { + final JsonObject other = new JsonObject(); + writeCellId(geolocation.getCellId(), other); + writeLocationAreaCode(geolocation.getLocationAreaCode(), other); + writeMobileCountryCode(geolocation.getMobileCountryCode(), other); + writeMobileNetworkCode(geolocation.getMobileNetworkCode(), other); + writeNetworkEntityAddress(geolocation.getNetworkEntityAddress(), other); + writeAgeOfLocationInfo(geolocation.getAgeOfLocationInfo(), other); + writeDeviceLatitude(geolocation.getDeviceLatitude(), other); + writeDeviceLongitude(geolocation.getDeviceLongitude(), other); + writeAccuracy(geolocation.getAccuracy(), other); + writeInternetAddress(geolocation.getInternetAddress(), other); + writePhysicalAddress(geolocation.getPhysicalAddress(), other); + writeFormattedAddress(geolocation.getFormattedAddress(), other); + writeLocationTimestamp(geolocation.getLocationTimestamp(), other); + writeEventGeofenceLatitude(geolocation.getEventGeofenceLatitude(), other); + writeEventGeofenceLongitude(geolocation.getEventGeofenceLongitude(), other); + writeRadius(geolocation.getRadius(), other); + object.add("geolocation_data", other); + } else { + object.add("geolocation_data", JsonNull.INSTANCE); + } + } + + protected void writeCellId(final String cellId, final HierarchicalStreamWriter writer) { + if (cellId != null) { + writer.startNode("CellId"); + writer.setValue(cellId); + writer.endNode(); + } + } + + protected void writeCellId(final String cellId, final JsonObject object) { + if (cellId != null) { + object.addProperty("cell_id", cellId); + } else { + object.add("cell_id", JsonNull.INSTANCE); + } + } + + protected void writeLocationAreaCode(final String locationAreaCode, final HierarchicalStreamWriter writer) { + if (locationAreaCode != null) { + writer.startNode("LocationAreaCode"); + writer.setValue(locationAreaCode); + writer.endNode(); + } + } + + protected void writeLocationAreaCode(final String locationAreaCode, final JsonObject object) { + if (locationAreaCode != null) { + object.addProperty("location_area_code", locationAreaCode); + } else { + object.add("location_area_code", JsonNull.INSTANCE); + } + } + + protected void writeMobileCountryCode(final Integer mobileCountryCode, final HierarchicalStreamWriter writer) { + if (mobileCountryCode != null) { + writer.startNode("MobileCountryCode"); + writer.setValue(mobileCountryCode.toString()); + writer.endNode(); + } + } + + protected void writeMobileCountryCode(final Integer mobileCountryCode, final JsonObject object) { + if (mobileCountryCode != null) { + object.addProperty("mobile_country_code", mobileCountryCode); + } else { + object.add("mobile_country_code", JsonNull.INSTANCE); + } + } + + protected void writeMobileNetworkCode(final String mobileNetworkCode, final HierarchicalStreamWriter writer) { + if (mobileNetworkCode != null) { + writer.startNode("MobileNetworkCode"); + writer.setValue(mobileNetworkCode.toString()); + writer.endNode(); + } + } + + protected void writeMobileNetworkCode(final String mobileNetworkCode, final JsonObject object) { + if (mobileNetworkCode != null) { + object.addProperty("mobile_network_code", mobileNetworkCode); + } else { + object.add("mobile_network_code", JsonNull.INSTANCE); + } + } + + protected void writeNetworkEntityAddress(final Long networkEntityAddress, final HierarchicalStreamWriter writer) { + if (networkEntityAddress != null) { + writer.startNode("NetworkEntityAddress"); + writer.setValue(networkEntityAddress.toString()); + writer.endNode(); + } + } + + protected void writeNetworkEntityAddress(final Long networkEntityAddress, final JsonObject object) { + if (networkEntityAddress != null) { + object.addProperty("network_entity_address", networkEntityAddress); + } else { + object.add("network_entity_address", JsonNull.INSTANCE); + } + } + + protected void writeAgeOfLocationInfo(final Integer ageOfLocationInfo, final HierarchicalStreamWriter writer) { + if (ageOfLocationInfo != null) { + writer.startNode("LocationAge"); + writer.setValue(ageOfLocationInfo.toString()); + writer.endNode(); + } + } + + protected void writeAgeOfLocationInfo(final Integer ageOfLocationInfo, final JsonObject object) { + if (ageOfLocationInfo != null) { + object.addProperty("location_age", ageOfLocationInfo); + } else { + object.add("location_age", JsonNull.INSTANCE); + } + } + + protected void writeDeviceLatitude(final String deviceLatitude, final HierarchicalStreamWriter writer) { + if (deviceLatitude != null) { + writer.startNode("DeviceLatitude"); + writer.setValue(deviceLatitude); + writer.endNode(); + } + } + + protected void writeDeviceLatitude(final String deviceLatitude, final JsonObject object) { + if (deviceLatitude != null) { + object.addProperty("device_latitude", deviceLatitude); + } else { + object.add("device_latitude", JsonNull.INSTANCE); + } + } + + protected void writeDeviceLongitude(final String deviceLongitude, final HierarchicalStreamWriter writer) { + if (deviceLongitude != null) { + writer.startNode("DeviceLongitude"); + writer.setValue(deviceLongitude); + writer.endNode(); + } + } + + protected void writeDeviceLongitude(final String deviceLongitude, final JsonObject object) { + if (deviceLongitude != null) { + object.addProperty("device_longitude", deviceLongitude); + } else { + object.add("device_longitude", JsonNull.INSTANCE); + } + } + + protected void writeAccuracy(final Long accuracy, final HierarchicalStreamWriter writer) { + if (accuracy != null) { + writer.startNode("Accuracy"); + writer.setValue(accuracy.toString()); + writer.endNode(); + } + } + + protected void writeAccuracy(final Long accuracy, final JsonObject object) { + if (accuracy != null) { + object.addProperty("accuracy", accuracy); + } else { + object.add("accuracy", JsonNull.INSTANCE); + } + } + + protected void writePhysicalAddress(final String physicalAddress, final HierarchicalStreamWriter writer) { + if (physicalAddress != null) { + writer.startNode("PhysicalAddress"); + writer.setValue(physicalAddress); + writer.endNode(); + } + } + + protected void writePhysicalAddress(final String physicalAddress, final JsonObject object) { + if (physicalAddress != null) { + object.addProperty("physical_address", physicalAddress); + } else { + object.add("physical_address", JsonNull.INSTANCE); + } + } + + protected void writeInternetAddress(final String internetAddress, final HierarchicalStreamWriter writer) { + if (internetAddress != null) { + writer.startNode("InternetAddress"); + writer.setValue(internetAddress); + writer.endNode(); + } + } + + protected void writeInternetAddress(final String internetAddress, final JsonObject object) { + if (internetAddress != null) { + object.addProperty("internet_address", internetAddress); + } else { + object.add("internet_address", JsonNull.INSTANCE); + } + } + + protected void writeFormattedAddress(final String formattedAddress, final HierarchicalStreamWriter writer) { + if (formattedAddress != null) { + writer.startNode("FormattedAddress"); + writer.setValue(formattedAddress); + writer.endNode(); + } + } + + protected void writeFormattedAddress(final String formattedAddress, final JsonObject object) { + if (formattedAddress != null) { + object.addProperty("formatted_address", formattedAddress); + } else { + object.add("formatted_address", JsonNull.INSTANCE); + } + } + + protected void writeLocationTimestamp(final DateTime locationTimestamp, final HierarchicalStreamWriter writer) { + if (locationTimestamp != null) { + writer.startNode("LocationTimestamp"); + writer.setValue(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(locationTimestamp.toDate())); + writer.endNode(); + } + } + + protected void writeLocationTimestamp(final DateTime locationTimestamp, final JsonObject object) { + if (locationTimestamp != null) { + object.addProperty("location_timestamp", + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).format(locationTimestamp.toDate())); + } else { + object.add("location_timestamp", JsonNull.INSTANCE); + } + } + + protected void writeEventGeofenceLatitude(final String eventGeofenceLatitude, final HierarchicalStreamWriter writer) { + if (eventGeofenceLatitude != null) { + writer.startNode("EventGeofenceLatitude"); + writer.setValue(eventGeofenceLatitude); + writer.endNode(); + } + } + + protected void writeEventGeofenceLatitude(final String eventGeofenceLatitude, final JsonObject object) { + if (eventGeofenceLatitude != null) { + object.addProperty("event_geofence_latitude", eventGeofenceLatitude); + } else { + object.add("event_geofence_latitude", JsonNull.INSTANCE); + } + } + + protected void writeEventGeofenceLongitude(final String eventGeofenceLongitude, final HierarchicalStreamWriter writer) { + if (eventGeofenceLongitude != null) { + writer.startNode("EventGeofenceLongitude"); + writer.setValue(eventGeofenceLongitude); + writer.endNode(); + } + } + + protected void writeEventGeofenceLongitude(final String eventGeofenceLongitude, final JsonObject object) { + if (eventGeofenceLongitude != null) { + object.addProperty("event_geofence_longitude", eventGeofenceLongitude); + } else { + object.add("event_geofence_longitude", JsonNull.INSTANCE); + } + } + + protected void writeRadius(final Long radius, final HierarchicalStreamWriter writer) { + if (radius != null) { + writer.startNode("Radius"); + writer.setValue(radius.toString()); + writer.endNode(); + } + } + + protected void writeRadius(final Long radius, final JsonObject object) { + if (radius != null) { + object.addProperty("radius", radius); + } else { + object.add("radius", JsonNull.INSTANCE); + } + } + + protected void writeGeolocationPositioningType(final String geolocationPositioningType, + final HierarchicalStreamWriter writer) { + if (geolocationPositioningType != null) { + writer.startNode("GeolocationPositioningType"); + writer.setValue(geolocationPositioningType.toString()); + writer.endNode(); + } + } + + protected void writeGeolocationPositioningType(final String geolocationPositioningType, final JsonObject object) { + if (geolocationPositioningType != null) { + object.addProperty("geolocation_positioning_type", geolocationPositioningType); + } else { + object.add("geolocation_positioning_type", JsonNull.INSTANCE); + } + } + + protected void writeLastGeolocationResponse(final String lastGeolocationResponse, final HierarchicalStreamWriter writer) { + if (lastGeolocationResponse != null) { + writer.startNode("LastGeolocationResponse"); + writer.setValue(lastGeolocationResponse.toString()); + writer.endNode(); + } + } + + protected void writeLastGeolocationResponse(final String lastGeolocationResponse, final JsonObject object) { + if (lastGeolocationResponse != null) { + object.addProperty("last_geolocation_response", lastGeolocationResponse); + } else { + object.add("last_geolocation_response", JsonNull.INSTANCE); + } + } + + protected void writeCause(final String cause, final HierarchicalStreamWriter writer) { + if (cause != null) { + writer.startNode("Cause"); + writer.setValue(cause.toString()); + writer.endNode(); + } + } + + protected void writeCause(final String cause, final JsonObject object) { + if (cause != null) { + object.addProperty("cause", cause); + } else { + object.add("cause", JsonNull.INSTANCE); + } + } + +} + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationListConverter.java new file mode 100644 index 0000000000..76007a5802 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/GeolocationListConverter.java @@ -0,0 +1,60 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http.converter; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Geolocation; +import org.restcomm.connect.dao.entities.GeolocationList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author Fernando Mendioroz + * + */ +@ThreadSafe +public class GeolocationListConverter extends AbstractConverter { + + public GeolocationListConverter (final Configuration configuration){ + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return GeolocationList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final GeolocationList list = (GeolocationList) object; + writer.startNode("Geolocations"); + for (final Geolocation geolocation : list.getGeolocations()) { + context.convertAnother(geolocation); + } + writer.endNode(); + } + +} + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberConverter.java new file mode 100644 index 0000000000..4703d006d7 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberConverter.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.http.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.commons.dao.Sid; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class IncomingPhoneNumberConverter extends AbstractConverter implements JsonSerializer { + public IncomingPhoneNumberConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return IncomingPhoneNumber.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final IncomingPhoneNumber incomingPhoneNumber = (IncomingPhoneNumber) object; + writer.startNode("IncomingPhoneNumber"); + writeSid(incomingPhoneNumber.getSid(), writer); + writeAccountSid(incomingPhoneNumber.getAccountSid(), writer); + writeFriendlyName(incomingPhoneNumber.getFriendlyName(), writer); + writePhoneNumber(incomingPhoneNumber.getPhoneNumber(), writer); + writeVoiceUrl(incomingPhoneNumber.getVoiceUrl(), writer); + writeVoiceMethod(incomingPhoneNumber.getVoiceMethod(), writer); + writeVoiceFallbackUrl(incomingPhoneNumber.getVoiceFallbackUrl(), writer); + writeVoiceFallbackMethod(incomingPhoneNumber.getVoiceFallbackMethod(), writer); + writeStatusCallback(incomingPhoneNumber.getStatusCallback(), writer); + writeStatusCallbackMethod(incomingPhoneNumber.getStatusCallbackMethod(), writer); + writeVoiceCallerIdLookup(incomingPhoneNumber.hasVoiceCallerIdLookup(), writer); + writeVoiceApplicationSid(incomingPhoneNumber.getVoiceApplicationSid(), writer); + if (incomingPhoneNumber.getVoiceApplicationSid() != null) + writeVoiceApplicationName(incomingPhoneNumber.getVoiceApplicationName(), writer); + writeDateCreated(incomingPhoneNumber.getDateCreated(), writer); + writeDateUpdated(incomingPhoneNumber.getDateUpdated(), writer); + writeSmsUrl(incomingPhoneNumber.getSmsUrl(), writer); + writeSmsMethod(incomingPhoneNumber.getSmsMethod(), writer); + writeSmsFallbackUrl(incomingPhoneNumber.getSmsFallbackUrl(), writer); + writeSmsFallbackMethod(incomingPhoneNumber.getSmsFallbackMethod(), writer); + writeSmsApplicationSid(incomingPhoneNumber.getSmsApplicationSid(), writer); + if (incomingPhoneNumber.getSmsApplicationSid() != null) + writeSmsApplicationName(incomingPhoneNumber.getSmsApplicationName(), writer); + writeUssdUrl(incomingPhoneNumber.getUssdUrl(), writer); + writeUssdMethod(incomingPhoneNumber.getUssdMethod(), writer); + writeUssdFallbackUrl(incomingPhoneNumber.getUssdFallbackUrl(), writer); + writeUssdFallbackMethod(incomingPhoneNumber.getUssdFallbackMethod(), writer); + writeUssdApplicationSid(incomingPhoneNumber.getUssdApplicationSid(), writer); + if (incomingPhoneNumber.getUssdApplicationSid() != null) + writeUssdApplicationName(incomingPhoneNumber.getUssdApplicationName(), writer); + writeReferUrl(incomingPhoneNumber.getReferUrl(), writer); + writeReferMethod(incomingPhoneNumber.getReferMethod(), writer); + writeReferApplicationSid(incomingPhoneNumber.getReferApplicationSid(), writer); + if (incomingPhoneNumber.getReferApplicationSid() != null) + writeReferApplicationName(incomingPhoneNumber.getReferApplicationName(), writer); + writeCapabilities(incomingPhoneNumber.isVoiceCapable(), incomingPhoneNumber.isSmsCapable(), incomingPhoneNumber.isMmsCapable(), incomingPhoneNumber.isFaxCapable(), writer); + writeApiVersion(incomingPhoneNumber.getApiVersion(), writer); + writeUri(incomingPhoneNumber.getUri(), writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final IncomingPhoneNumber incomingPhoneNumber, final Type type, + final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(incomingPhoneNumber.getSid(), object); + writeAccountSid(incomingPhoneNumber.getAccountSid(), object); + writeFriendlyName(incomingPhoneNumber.getFriendlyName(), object); + writePhoneNumber(incomingPhoneNumber.getPhoneNumber(), object); + writeVoiceUrl(incomingPhoneNumber.getVoiceUrl(), object); + writeVoiceMethod(incomingPhoneNumber.getVoiceMethod(), object); + writeVoiceFallbackUrl(incomingPhoneNumber.getVoiceFallbackUrl(), object); + writeVoiceFallbackMethod(incomingPhoneNumber.getVoiceFallbackMethod(), object); + writeStatusCallback(incomingPhoneNumber.getStatusCallback(), object); + writeStatusCallbackMethod(incomingPhoneNumber.getStatusCallbackMethod(), object); + writeVoiceCallerIdLookup(incomingPhoneNumber.hasVoiceCallerIdLookup(), object); + writeVoiceApplicationSid(incomingPhoneNumber.getVoiceApplicationSid(), object); + if (incomingPhoneNumber.getVoiceApplicationSid() != null) + writeVoiceApplicationName(incomingPhoneNumber.getVoiceApplicationName(), object); + writeDateCreated(incomingPhoneNumber.getDateCreated(), object); + writeDateUpdated(incomingPhoneNumber.getDateUpdated(), object); + writeSmsUrl(incomingPhoneNumber.getSmsUrl(), object); + writeSmsMethod(incomingPhoneNumber.getSmsMethod(), object); + writeSmsFallbackUrl(incomingPhoneNumber.getSmsFallbackUrl(), object); + writeSmsFallbackMethod(incomingPhoneNumber.getSmsFallbackMethod(), object); + writeSmsApplicationSid(incomingPhoneNumber.getSmsApplicationSid(), object); + if (incomingPhoneNumber.getSmsApplicationSid() != null) + writeSmsApplicationName(incomingPhoneNumber.getSmsApplicationName(), object); + writeUssdUrl(incomingPhoneNumber.getUssdUrl(), object); + writeUssdMethod(incomingPhoneNumber.getUssdMethod(), object); + writeUssdFallbackUrl(incomingPhoneNumber.getUssdFallbackUrl(), object); + writeUssdFallbackMethod(incomingPhoneNumber.getUssdFallbackMethod(), object); + writeUssdApplicationSid(incomingPhoneNumber.getUssdApplicationSid(), object); + if (incomingPhoneNumber.getUssdApplicationSid() != null) + writeUssdApplicationName(incomingPhoneNumber.getUssdApplicationName(), object); + writeReferUrl(incomingPhoneNumber.getReferUrl(), object); + writeReferMethod(incomingPhoneNumber.getReferMethod(), object); + writeReferApplicationSid(incomingPhoneNumber.getReferApplicationSid(), object); + if (incomingPhoneNumber.getReferApplicationSid() != null) + writeReferApplicationName(incomingPhoneNumber.getReferApplicationName(), object); + writeCapabilities(incomingPhoneNumber.isVoiceCapable(), incomingPhoneNumber.isSmsCapable(), incomingPhoneNumber.isMmsCapable(), incomingPhoneNumber.isFaxCapable(), object); + writeApiVersion(incomingPhoneNumber.getApiVersion(), object); + writeUri(incomingPhoneNumber.getUri(), object); + return object; + } + + private void writeSmsApplicationSid(final Sid smsApplicationSid, final HierarchicalStreamWriter writer) { + if (smsApplicationSid != null) { + writer.startNode("SmsApplicationSid"); + writer.setValue(smsApplicationSid.toString()); + writer.endNode(); + } + } + + private void writeSmsApplicationSid(final Sid smsApplicationSid, final JsonObject object) { + if (smsApplicationSid != null) { + object.addProperty("sms_application_sid", smsApplicationSid.toString()); + } else { + object.add("sms_application_sid", JsonNull.INSTANCE); + } + } + + private void writeUssdApplicationSid(final Sid ussdApplicationSid, final HierarchicalStreamWriter writer) { + if (ussdApplicationSid != null) { + writer.startNode("UssdApplicationSid"); + writer.setValue(ussdApplicationSid.toString()); + writer.endNode(); + } + } + + private void writeUssdApplicationSid(final Sid ussdApplicationSid, final JsonObject object) { + if (ussdApplicationSid != null) { + object.addProperty("ussd_application_sid", ussdApplicationSid.toString()); + } else { + object.add("ussd_application_sid", JsonNull.INSTANCE); + } + } + + private void writeReferApplicationSid(final Sid referApplicationSid, final JsonObject object) { + if (referApplicationSid != null) { + object.addProperty("refer_application_sid", referApplicationSid.toString()); + } else { + object.add("refer_application_sid", JsonNull.INSTANCE); + } + } + + private void writeReferApplicationSid(final Sid referApplicationSid, final HierarchicalStreamWriter writer) { + if (referApplicationSid != null) { + writer.startNode("ReferApplicationSid"); + writer.setValue(referApplicationSid.toString()); + writer.endNode(); + } + } + + private void writeVoiceApplicationName(final String voiceApplicationName, final JsonObject object) { + if (voiceApplicationName != null) + object.addProperty("voice_application_name", voiceApplicationName); + else + object.add("voice_application_name", JsonNull.INSTANCE); + } + + private void writeVoiceApplicationName(final String voiceApplicationName, final HierarchicalStreamWriter writer) { + writer.startNode("VoiceApplicationName"); + writer.setValue(voiceApplicationName); + writer.endNode(); + } + + private void writeSmsApplicationName(final String smsApplicationName, final JsonObject object) { + if (smsApplicationName != null) + object.addProperty("sms_application_name", smsApplicationName); + else + object.add("sms_application_name", JsonNull.INSTANCE); + } + + private void writeSmsApplicationName(final String smsApplicationName, final HierarchicalStreamWriter writer) { + writer.startNode("SmsApplicationName"); + writer.setValue(smsApplicationName); + writer.endNode(); + } + + private void writeUssdApplicationName(final String ussdApplicationName, final JsonObject object) { + if (ussdApplicationName != null) + object.addProperty("ussd_application_name", ussdApplicationName); + else + object.add("ussd_application_name", JsonNull.INSTANCE); + } + + private void writeUssdApplicationName(final String ussdApplicationName, final HierarchicalStreamWriter writer) { + writer.startNode("UssdApplicationName"); + writer.setValue(ussdApplicationName); + writer.endNode(); + } + + private void writeReferApplicationName(final String referApplicationName, final JsonObject object) { + if (referApplicationName != null) + object.addProperty("refer_application_name", referApplicationName); + else + object.add("refer_application_name", JsonNull.INSTANCE); + } + + private void writeReferApplicationName(final String referApplicationName, final HierarchicalStreamWriter writer) { + writer.startNode("ReferApplicationName"); + writer.setValue(referApplicationName); + writer.endNode(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberListConverter.java new file mode 100644 index 0000000000..a1e8543570 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/IncomingPhoneNumberListConverter.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.http.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberList; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class IncomingPhoneNumberListConverter extends AbstractConverter + implements JsonSerializer { + + Integer page, pageSize, total; + String pathUri; + + public IncomingPhoneNumberListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return IncomingPhoneNumberList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final IncomingPhoneNumberList list = (IncomingPhoneNumberList) object; + writer.startNode("IncomingPhoneNumbers"); + writer.addAttribute("page", String.valueOf(page)); + writer.addAttribute("numpages", String.valueOf(getTotalPages())); + writer.addAttribute("pagesize", String.valueOf(pageSize)); + writer.addAttribute("total", String.valueOf(getTotalPages())); + writer.addAttribute("start", getFirstIndex()); + writer.addAttribute("end", getLastIndex(list)); + writer.addAttribute("uri", pathUri); + writer.addAttribute("firstpageuri", getFirstPageUri()); + writer.addAttribute("previouspageuri", getPreviousPageUri()); + writer.addAttribute("nextpageuri", getNextPageUri(list)); + writer.addAttribute("lastpageuri", getLastPageUri()); + for (final IncomingPhoneNumber incomingPhoneNumber : list.getIncomingPhoneNumbers()) { + context.convertAnother(incomingPhoneNumber); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(IncomingPhoneNumberList list, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (IncomingPhoneNumber phoneNumber : list.getIncomingPhoneNumbers()) { + array.add(context.serialize(phoneNumber)); + } + + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(list)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(list)); + result.addProperty("last_page_uri", getLastPageUri()); + } + + result.add("incomingPhoneNumbers", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(IncomingPhoneNumberList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getIncomingPhoneNumbers().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(IncomingPhoneNumberList list) { + String lastSid = (page == getTotalPages()) ? "null" + : list.getIncomingPhoneNumbers().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" + : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverter.java new file mode 100644 index 0000000000..0cba61c59b --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverter.java @@ -0,0 +1,157 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http.converter; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.restcomm.connect.commons.Version; +import org.restcomm.connect.commons.util.UriUtils; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.MonitoringServiceResponse; + +import java.lang.reflect.Type; +import java.util.Iterator; +import java.util.Map; + +/** + * @author gvagenas + * + */ +public class MonitoringServiceConverter extends AbstractConverter implements JsonSerializer{ + + private String dateTimeNow; + + public MonitoringServiceConverter(Configuration configuration) { + super(configuration); + DateTime now = DateTime.now(); + DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE, dd MMM yyyy kk:mm:ss"); + dateTimeNow = fmt.print(now); + + } + + @Override + public boolean canConvert(final Class klass) { + return MonitoringServiceResponse.class.equals(klass); + } + + @Override + public JsonElement serialize(MonitoringServiceResponse monitoringServiceResponse, Type typeOfSrc, JsonSerializationContext context) { + final Map countersMap = monitoringServiceResponse.getCountersMap(); + final Map durationMap = monitoringServiceResponse.getDurationMap(); + JsonObject result = new JsonObject(); + JsonObject metrics = new JsonObject(); + JsonArray callsArray = new JsonArray(); + + //First add InstanceId and Version details + result.addProperty("DateTime", dateTimeNow); + result.addProperty("InstanceId", monitoringServiceResponse.getInstanceId().getId().toString()); + result.addProperty("Version", Version.getVersion()); + result.addProperty("Revision", Version.getRevision()); + + Iterator counterIterator = countersMap.keySet().iterator(); + while (counterIterator.hasNext()) { + String counter = counterIterator.next(); + metrics.addProperty(counter, countersMap.get(counter)); + } + Iterator durationIterator = durationMap.keySet().iterator(); + while (durationIterator.hasNext()) { + String durationKey = durationIterator.next(); + metrics.addProperty(durationKey, durationMap.get(durationKey)); + } + result.add("Metrics", metrics); + + if (monitoringServiceResponse.isWithCallDetailsList()) { + if (monitoringServiceResponse.getCallDetailsList() != null && monitoringServiceResponse.getCallDetailsList().size() > 0) { + for (CallInfo callInfo : monitoringServiceResponse.getCallDetailsList()) { + callsArray.add(context.serialize(callInfo)); + } + } + result.add("LiveCallDetails", callsArray); + } else { + result.addProperty("LiveCallDetails", UriUtils.resolve(monitoringServiceResponse.getCallDetailsUrl()).toString()); + } + return result; + } + + @Override + public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + final MonitoringServiceResponse monitoringServiceResponse = (MonitoringServiceResponse) object; + final Map durationMap = monitoringServiceResponse.getDurationMap(); + final Map countersMap = monitoringServiceResponse.getCountersMap(); + Iterator counterIterator = countersMap.keySet().iterator(); + Iterator durationIterator = durationMap.keySet().iterator(); + + writer.startNode("DateTime"); + writer.setValue(dateTimeNow); + writer.endNode(); + + writer.startNode("InstanceId"); + writer.setValue(monitoringServiceResponse.getInstanceId().getId().toString()); + writer.endNode(); + + writer.startNode("Version"); + writer.setValue(Version.getVersion()); + writer.endNode(); + + writer.startNode("Revision"); + writer.setValue(Version.getRevision()); + writer.endNode(); + + writer.startNode("Metrics"); + while (counterIterator.hasNext()) { + String counter = counterIterator.next(); + writer.startNode(counter); + writer.setValue(String.valueOf(countersMap.get(counter))); + writer.endNode(); + } + while (durationIterator.hasNext()) { + String durationKey = durationIterator.next(); + writer.startNode(durationKey); + writer.setValue(String.valueOf(durationMap.get(durationKey))); + writer.endNode(); + } + writer.endNode(); + + if (monitoringServiceResponse.isWithCallDetailsList()) { + if (monitoringServiceResponse.getCallDetailsList() != null && monitoringServiceResponse.getCallDetailsList().size() > 0) { + writer.startNode("LiveCallDetails"); + + for (final CallInfo callInfo : monitoringServiceResponse.getCallDetailsList()) { + context.convertAnother(callInfo); + } + writer.endNode(); + } else { + writer.startNode("LiveCallDetails"); + writer.setValue(UriUtils.resolve(monitoringServiceResponse.getCallDetailsUrl()).toString()); + writer.endNode(); + } + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverterCallDetails.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverterCallDetails.java new file mode 100644 index 0000000000..fa8fecdf1d --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/MonitoringServiceConverterCallDetails.java @@ -0,0 +1,112 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.restcomm.connect.http.converter; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.restcomm.connect.commons.Version; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.monitoringservice.LiveCallsDetails; +import org.restcomm.connect.telephony.api.CallInfo; + +import java.lang.reflect.Type; +import java.util.List; + +/** + * @author gvagenas + * + */ +public class MonitoringServiceConverterCallDetails extends AbstractConverter implements JsonSerializer{ + + private String dateTimeNow; + + public MonitoringServiceConverterCallDetails (Configuration configuration) { + super(configuration); + DateTime now = DateTime.now(); + DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE, dd MMM yyyy kk:mm:ss"); + dateTimeNow = fmt.print(now); + } + + @Override + public boolean canConvert(final Class klass) { + return (List.class.equals(klass)); + } + + @Override + public JsonElement serialize(LiveCallsDetails callDetails, Type typeOfSrc, JsonSerializationContext context) { + JsonObject result = new JsonObject(); + JsonArray callsArray = new JsonArray(); + + //First add InstanceId and Version details + result.addProperty("DateTime", dateTimeNow); + result.addProperty("InstanceId", RestcommConfiguration.getInstance().getMain().getInstanceId()); + result.addProperty("Version", Version.getVersion()); + result.addProperty("Revision", Version.getRevision()); + + List liveCalls = callDetails.getCallDetails(); + + if (liveCalls.size() > 0) + for (CallInfo callInfo: liveCalls) { + callsArray.add(context.serialize(callInfo)); + } + result.add("LiveCallDetails", callsArray); + return result; + } + + @Override + public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + final List callDetails = (List) object; + + writer.startNode("DateTime"); + writer.setValue(dateTimeNow); + writer.endNode(); + + writer.startNode("InstanceId"); + writer.setValue(RestcommConfiguration.getInstance().getMain().getInstanceId()); + writer.endNode(); + + writer.startNode("Version"); + writer.setValue(Version.getVersion()); + writer.endNode(); + + writer.startNode("Revision"); + writer.setValue(Version.getRevision()); + writer.endNode(); + + if (callDetails.size() > 0) { + writer.startNode("LiveCallDetails"); + + for (final CallInfo callInfo : callDetails) { + context.convertAnother(callInfo); + } + writer.endNode(); + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationConverter.java similarity index 97% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationConverter.java index 3e6aac5a71..539bcaf5c6 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/NotificationConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationConverter.java @@ -17,15 +17,15 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import java.net.URI; import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Notification; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Notification; import com.google.gson.JsonElement; import com.google.gson.JsonNull; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationListConverter.java new file mode 100644 index 0000000000..8d167d2e77 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/NotificationListConverter.java @@ -0,0 +1,139 @@ +/* + * 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.converter; + +import com.google.gson.JsonArray; +import java.lang.reflect.Type; + +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.dao.entities.NotificationList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class NotificationListConverter extends AbstractConverter implements JsonSerializer { + Integer page, pageSize, total; + String pathUri; + + public NotificationListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return NotificationList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final NotificationList list = (NotificationList) object; + writer.startNode("Notifications"); + for (final Notification notification : list.getNotifications()) { + context.convertAnother(notification); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(NotificationList ntfList, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (Notification cdr : ntfList.getNotifications()) { + array.add(context.serialize(cdr)); + } + + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(ntfList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(ntfList)); + result.addProperty("last_page_uri", getLastPageUri()); + } + + result.add("notifications", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(NotificationList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getNotifications().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(NotificationList list) { + String lastSid = (page == getTotalPages()) ? "null" : list.getNotifications().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationConverter.java new file mode 100644 index 0000000000..e6e275b12d --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationConverter.java @@ -0,0 +1,74 @@ +/* + * 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.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Organization; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author maria farooq + */ +@ThreadSafe +public final class OrganizationConverter extends AbstractConverter implements JsonSerializer { + + public OrganizationConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Organization.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Organization organization = (Organization) object; + writer.startNode("Organization"); + writeSid(organization.getSid(), writer); + writeDomainName(organization.getDomainName(), writer); + writeStatus(organization.getStatus().toString(), writer); + writeDateCreated(organization.getDateCreated(), writer); + writeDateUpdated(organization.getDateUpdated(), writer); + writer.endNode(); + } + + @Override + public JsonElement serialize(final Organization organization, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(organization.getSid(), object); + writeDomainName(organization.getDomainName(), object); + writeStatus(organization.getStatus().toString(), object); + writeDateCreated(organization.getDateCreated(), object); + writeDateUpdated(organization.getDateUpdated(), object); + return object; + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationListConverter.java new file mode 100644 index 0000000000..ec1bd2c4f0 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OrganizationListConverter.java @@ -0,0 +1,52 @@ +/* + * 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.converter; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.entities.OrganizationList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author maria farooq + */ +public final class OrganizationListConverter extends AbstractConverter { + public OrganizationListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return OrganizationList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final OrganizationList list = (OrganizationList) object; + writer.startNode("Organizations"); + for (final Organization organization : list.getOrganizations()) { + context.convertAnother(organization); + } + writer.endNode(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdConverter.java similarity index 94% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdConverter.java index ef4f3ae191..1210eeb75b 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdConverter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerId; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.OutgoingCallerId; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdListConverter.java index f81755ffcc..a63afd850d 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/OutgoingCallerIdListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/OutgoingCallerIdListConverter.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerId; -import org.mobicents.servlet.restcomm.entities.OutgoingCallerIdList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.OutgoingCallerId; +import org.restcomm.connect.dao.entities.OutgoingCallerIdList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingConverter.java new file mode 100644 index 0000000000..f77ea3a009 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingConverter.java @@ -0,0 +1,100 @@ +/* + * 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.converter; + +import java.lang.reflect.Type; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.amazonS3.RecordingSecurityLevel; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Recording; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class RecordingConverter extends AbstractConverter implements JsonSerializer { + + private RecordingSecurityLevel securityLevel = RecordingSecurityLevel.SECURE; + + public RecordingConverter(final Configuration configuration) { + super(configuration); + } + + public void setSecurityLevel(final RecordingSecurityLevel securityLevel) { + this.securityLevel = securityLevel; + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Recording.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Recording recording = (Recording) object; + writer.startNode("Recording"); + writeSid(recording.getSid(), writer); + writeDateCreated(recording.getDateCreated(), writer); + writeDateUpdated(recording.getDateUpdated(), writer); + writeAccountSid(recording.getAccountSid(), writer); + writeCallSid(recording.getCallSid(), writer); + writeDuration(recording.getDuration(), writer); + writeApiVersion(recording.getApiVersion(), writer); + writeUri(recording.getUri(), writer); + writer.startNode("FileUri"); + writer.setValue(recording.getFileUri().toString()); + writer.endNode(); + if (securityLevel.equals(RecordingSecurityLevel.NONE) && recording.getS3Uri() != null) { + writer.startNode("S3Uri"); + writer.setValue(recording.getS3Uri().toString()); + writer.endNode(); + } + writer.endNode(); + } + + @Override + public JsonElement serialize(final Recording recording, final Type type, final JsonSerializationContext context) { + final JsonObject object = new JsonObject(); + writeSid(recording.getSid(), object); + writeDateCreated(recording.getDateCreated(), object); + writeDateUpdated(recording.getDateUpdated(), object); + writeAccountSid(recording.getAccountSid(), object); + writeCallSid(recording.getCallSid(), object); + writeDuration(recording.getDuration(), object); + writeApiVersion(recording.getApiVersion(), object); + writeUri(recording.getUri(), object); + if (recording.getFileUri() != null) { + object.addProperty("file_uri", recording.getFileUri().toString()); + } + if (securityLevel.equals(RecordingSecurityLevel.NONE) && recording.getS3Uri() != null) { + object.addProperty("s3_uri", recording.getS3Uri().toString()); + } + return object; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingListConverter.java new file mode 100644 index 0000000000..28eb7fb254 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RecordingListConverter.java @@ -0,0 +1,138 @@ +/* + * 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.converter; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.RecordingList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import java.lang.reflect.Type; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class RecordingListConverter extends AbstractConverter implements JsonSerializer { + Integer page, pageSize, total; + String pathUri; + + public RecordingListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return RecordingList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final RecordingList list = (RecordingList) object; + writer.startNode("Recordings"); + for (final Recording recording : list.getRecordings()) { + context.convertAnother(recording); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(RecordingList recList, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (Recording cdr : recList.getRecordings()) { + array.add(context.serialize(cdr)); + } + + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(recList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(recList)); + result.addProperty("last_page_uri", getLastPageUri()); + } + + result.add("recordings", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(RecordingList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getRecordings().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(RecordingList list) { + String lastSid = (page == getTotalPages()) ? "null" : list.getRecordings().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationConverter.java similarity index 96% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationConverter.java index 1037587b8c..2008931fbb 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationConverter.java @@ -17,14 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Registration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Registration; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationListConverter.java index 4494c0ca7e..6835805411 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RegistrationListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RegistrationListConverter.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Registration; -import org.mobicents.servlet.restcomm.entities.RegistrationList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Registration; +import org.restcomm.connect.dao.entities.RegistrationList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RestCommResponseConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RestCommResponseConverter.java similarity index 89% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RestCommResponseConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RestCommResponseConverter.java index 2c75e3e9b1..53d6ac3cfa 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/RestCommResponseConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/RestCommResponseConverter.java @@ -17,14 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.RestCommResponse; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.RestCommResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeConverter.java similarity index 95% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeConverter.java index 963d87b5fa..669f9808a4 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeConverter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.ShortCode; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.ShortCode; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeListConverter.java similarity index 87% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeListConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeListConverter.java index 4511538979..2e36ff2ecf 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/ShortCodeListConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/ShortCodeListConverter.java @@ -17,12 +17,12 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.ShortCode; -import org.mobicents.servlet.restcomm.entities.ShortCodeList; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.ShortCode; +import org.restcomm.connect.dao.entities.ShortCodeList; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageConverter.java similarity index 97% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageConverter.java index b2db438ba6..769ee69ce8 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/SmsMessageConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageConverter.java @@ -17,13 +17,13 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessage; import com.google.gson.JsonElement; import com.google.gson.JsonNull; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageListConverter.java new file mode 100644 index 0000000000..c0574d5d69 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/SmsMessageListConverter.java @@ -0,0 +1,140 @@ +/* + * 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.converter; + +import com.google.gson.JsonArray; +import java.lang.reflect.Type; + +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessageList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class SmsMessageListConverter extends AbstractConverter implements JsonSerializer { + + Integer page, pageSize, total; + String pathUri; + + public SmsMessageListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return SmsMessageList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final SmsMessageList list = (SmsMessageList) object; + writer.startNode("SMSMessages"); + for (final SmsMessage sms : list.getSmsMessages()) { + context.convertAnother(sms); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(SmsMessageList smsList, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (SmsMessage cdr : smsList.getSmsMessages()) { + array.add(context.serialize(cdr)); + } + + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(smsList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(smsList)); + result.addProperty("last_page_uri", getLastPageUri()); + } + + result.add("messages", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(SmsMessageList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getSmsMessages().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(SmsMessageList list) { + String lastSid = (page == getTotalPages()) ? "null" : list.getSmsMessages().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionConverter.java similarity index 94% rename from restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionConverter.java rename to restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionConverter.java index 756887ed57..b39f3cb7f3 100644 --- a/restcomm/restcomm.http/src/main/java/org/mobicents/servlet/restcomm/http/converter/TranscriptionConverter.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionConverter.java @@ -17,14 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.http.converter; +package org.restcomm.connect.http.converter; import java.lang.reflect.Type; import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.annotations.concurrency.ThreadSafe; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.Transcription; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Transcription; import com.google.gson.JsonElement; import com.google.gson.JsonNull; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionListConverter.java new file mode 100644 index 0000000000..2b00187b2f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/TranscriptionListConverter.java @@ -0,0 +1,138 @@ +/* + * 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.converter; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Transcription; +import org.restcomm.connect.dao.entities.TranscriptionList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import java.lang.reflect.Type; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@ThreadSafe +public final class TranscriptionListConverter extends AbstractConverter implements JsonSerializer { + Integer page, pageSize, total; + String pathUri; + + public TranscriptionListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return TranscriptionList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final TranscriptionList list = (TranscriptionList) object; + writer.startNode("Transcriptions"); + for (final Transcription transcription : list.getTranscriptions()) { + context.convertAnother(transcription); + } + writer.endNode(); + } + + @Override + public JsonObject serialize(TranscriptionList transList, Type type, JsonSerializationContext context) { + + JsonObject result = new JsonObject(); + + JsonArray array = new JsonArray(); + for (Transcription cdr : transList.getTranscriptions()) { + array.add(context.serialize(cdr)); + } + + if (total != null && pageSize != null && page != null) { + result.addProperty("page", page); + result.addProperty("num_pages", getTotalPages()); + result.addProperty("page_size", pageSize); + result.addProperty("total", total); + result.addProperty("start", getFirstIndex()); + result.addProperty("end", getLastIndex(transList)); + result.addProperty("uri", pathUri); + result.addProperty("first_page_uri", getFirstPageUri()); + result.addProperty("previous_page_uri", getPreviousPageUri()); + result.addProperty("next_page_uri", getNextPageUri(transList)); + result.addProperty("last_page_uri", getLastPageUri()); + } + + result.add("transcriptions", array); + + return result; + } + + private int getTotalPages() { + return total / pageSize; + } + + private String getFirstIndex() { + return String.valueOf(page * pageSize); + } + + private String getLastIndex(TranscriptionList list) { + return String.valueOf((page == getTotalPages()) ? (page * pageSize) + list.getTranscriptions().size() + : (pageSize - 1) + (page * pageSize)); + } + + private String getFirstPageUri() { + return pathUri + "?Page=0&PageSize=" + pageSize; + } + + private String getPreviousPageUri() { + return ((page == 0) ? "null" : pathUri + "?Page=" + (page - 1) + "&PageSize=" + pageSize); + } + + private String getNextPageUri(TranscriptionList list) { + String lastSid = (page == getTotalPages()) ? "null" : list.getTranscriptions().get(pageSize - 1).getSid().toString(); + return (page == getTotalPages()) ? "null" : pathUri + "?Page=" + (page + 1) + "&PageSize=" + pageSize + "&AfterSid=" + + lastSid; + } + + private String getLastPageUri() { + return pathUri + "?Page=" + getTotalPages() + "&PageSize=" + pageSize; + } + + public void setPage(Integer page) { + this.page = page; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public void setCount(Integer count) { + this.total = count; + } + + public void setPathUri(String pathUri) { + this.pathUri = pathUri; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageConverter.java new file mode 100644 index 0000000000..a8d17dce91 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageConverter.java @@ -0,0 +1,200 @@ +/* + * 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.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import org.apache.commons.configuration.Configuration; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import org.joda.time.DateTime; +import org.restcomm.connect.dao.entities.Usage; + +import java.lang.reflect.Type; +import java.net.URI; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +public final class UsageConverter extends AbstractConverter implements JsonSerializer { + public UsageConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return Usage.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Usage number = (Usage) object; + writer.startNode("UsageRecord"); + writeCategory(number.getCategory(), writer); + writeDescription(number.getDescription(), writer); + writeAccountSid(number.getAccountSid(), writer); + writeStartDate(number.getStartDate(), writer); + writeEndDate(number.getEndDate(), writer); + writeUsage(number.getUsage(), writer); + writeUsageUnit(number.getUsageUnit(), writer); + writeCount(number.getCount(), writer); + writeCountUnit(number.getCountUnit(), writer); + writePrice(number.getPrice(), writer); + writePriceUnit(number.getPriceUnit(), writer); + writeUri(number.getUri(), writer); + writer.endNode(); + } + + private void writeCategory(final Usage.Category category, final HierarchicalStreamWriter writer) { + writer.startNode("Category"); + if (category != null) { + writer.setValue(category.toString()); + } + writer.endNode(); + } + + private void writeCategory(final Usage.Category category, final JsonObject object) { + object.addProperty("category", category.toString()); + } + + private void writeDescription(final String description, final HierarchicalStreamWriter writer) { + writer.startNode("Description"); + if (description != null) { + writer.setValue(description.toString()); + } + writer.endNode(); + } + + private void writeDescription(final String description, final JsonObject object) { + object.addProperty("description", description); + } + + private void writeStartDate(final DateTime startDate, final HierarchicalStreamWriter writer) { + writer.startNode("StartDate"); + if (startDate != null) { + writer.setValue(startDate.toString("yyyy-MM-dd")); + } + writer.endNode(); + } + + private void writeStartDate(final DateTime startDate, final JsonObject object) { + object.addProperty("start_date", startDate.toString("yyyy-MM-dd")); + } + + private void writeEndDate(final DateTime endDate, final HierarchicalStreamWriter writer) { + writer.startNode("EndDate"); + if (endDate != null) { + writer.setValue(endDate.toString("yyyy-MM-dd")); + } + writer.endNode(); + } + + private void writeEndDate(final DateTime endDate, final JsonObject object) { + object.addProperty("end_date", endDate.toString("yyyy-MM-dd")); + } + + private void writeUsage(final Long usage, final HierarchicalStreamWriter writer) { + writer.startNode("Usage"); + if (usage != null) { + writer.setValue(usage.toString()); + } + writer.endNode(); + } + + private void writeUsage(final Long usage, final JsonObject object) { + object.addProperty("usage", usage.toString()); + } + + private void writeUsageUnit(final String usageUnit, final HierarchicalStreamWriter writer) { + writer.startNode("UsageUnit"); + if (usageUnit != null) { + writer.setValue(usageUnit); + } + writer.endNode(); + } + + private void writeUsageUnit(final String usageUnit, final JsonObject object) { + object.addProperty("usage_unit", usageUnit); + } + + private void writeCount(final Long count, final HierarchicalStreamWriter writer) { + writer.startNode("Count"); + if (count != null) { + writer.setValue(count.toString()); + } + writer.endNode(); + } + + private void writeCount(final Long count, final JsonObject object) { + object.addProperty("count", count.toString()); + } + + private void writeCountUnit(final String countUnit, final HierarchicalStreamWriter writer) { + writer.startNode("CountUnit"); + if (countUnit != null) { + writer.setValue(countUnit.toString()); + } + writer.endNode(); + } + + private void writeCountUnit(final String countUnit, final JsonObject object) { + object.addProperty("count_unit", countUnit); + } + + private void writePriceUnit(final String priceUnit, final HierarchicalStreamWriter writer) { + writer.startNode("PriceUnit"); + if (priceUnit != null) { + writer.setValue(priceUnit.toString()); + } + writer.endNode(); + } + + private void writePriceUnit(final String priceUnit, final JsonObject object) { + object.addProperty("price_unit", priceUnit); + } + + protected void writeUri(final URI uri, final JsonObject object) { + object.addProperty("uri", uri.toString()); + } + + @Override + public JsonElement serialize(Usage usage, Type type, JsonSerializationContext jsonSerializationContext) { + final JsonObject object = new JsonObject(); + writeCategory(usage.getCategory(), object); + writeDescription(usage.getDescription(), object); + writeAccountSid(usage.getAccountSid(), object); + writeStartDate(usage.getStartDate(), object); + writeEndDate(usage.getEndDate(), object); + writeUsage(usage.getUsage(), object); + writeUsageUnit(usage.getUsageUnit(), object); + writeCount(usage.getCount(), object); + writeCountUnit(usage.getCountUnit(), object); + writePrice(usage.getPrice(), object); + writePriceUnit(usage.getPriceUnit(), object); + writeUri(usage.getUri(), object); + return object; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageListConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageListConverter.java new file mode 100644 index 0000000000..15671189c6 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/UsageListConverter.java @@ -0,0 +1,54 @@ +/* + * 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.converter; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe; +import org.restcomm.connect.dao.entities.Usage; +import org.restcomm.connect.dao.entities.UsageList; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author brainslog@gmail.com (Alexandre Mendonca) + */ +@ThreadSafe +public final class UsageListConverter extends AbstractConverter { + public UsageListConverter(final Configuration configuration) { + super(configuration); + } + + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(final Class klass) { + return UsageList.class.equals(klass); + } + + @Override + public void marshal(final Object object, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final UsageList list = (UsageList) object; + writer.startNode("UsageRecords"); + for (final Usage usage : list.getUsages()) { + context.convertAnother(usage); + } + writer.endNode(); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/VersionConverter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/VersionConverter.java new file mode 100644 index 0000000000..1ab6ffbf78 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/converter/VersionConverter.java @@ -0,0 +1,83 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2013, Telestax Inc and individual contributors + * by the @authors tag. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.restcomm.connect.http.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.VersionEntity; + +import java.lang.reflect.Type; + +/** + * Created by gvagenas on 1/19/16. + */ +public class VersionConverter extends AbstractConverter implements JsonSerializer { + + public VersionConverter(Configuration configuration) { + super(configuration); + } + + @Override + public boolean canConvert(Class klass) { + return VersionEntity.class.equals(klass); + } + + @Override + public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + final VersionEntity versionEntity = (VersionEntity) object; + String version = versionEntity.getVersion(); + String revision = versionEntity.getRevision(); + String name = versionEntity.getName(); + String date = versionEntity.getDate(); + + writer.startNode("Name"); + writer.setValue(name+" Restcomm"); + writer.endNode(); + + writer.startNode("Version"); + writer.setValue(version); + writer.endNode(); + + writer.startNode("Revision"); + writer.setValue(revision); + writer.endNode(); + + writer.startNode("Date"); + writer.setValue(date); + writer.endNode(); + } + + @Override + public JsonElement serialize(VersionEntity versionEntity, Type type, JsonSerializationContext jsonSerializationContext) { + JsonObject result = new JsonObject(); + result.addProperty("Name", versionEntity.getName()+" Restcomm"); + result.addProperty("Version", versionEntity.getVersion()); + result.addProperty("Revision", versionEntity.getRevision()); + result.addProperty("Date", versionEntity.getDate()); + return result; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/cors/CorsFilter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/cors/CorsFilter.java new file mode 100644 index 0000000000..9dcb847f88 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/cors/CorsFilter.java @@ -0,0 +1,108 @@ +/* + * 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.cors; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerResponse; +import com.sun.jersey.spi.container.ContainerResponseFilter; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet; +import org.restcomm.connect.commons.configuration.sets.impl.RcmlserverConfigurationSetImpl; +import org.restcomm.connect.commons.configuration.sources.ApacheConfigurationSource; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; +import java.io.File; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +@Provider +public class CorsFilter implements ContainerResponseFilter { + private final Logger logger = Logger.getLogger(CorsFilter.class); + + @Context + private HttpServletRequest servletRequest; + + // we initialize this lazily upon first request since it can't be injected through the @Context annotation (it didn't work) + private ServletContext lazyServletContext; + + String allowedOrigin; + + // We return Access-* headers only in case allowedOrigin is present and equals to the 'Origin' header. + @Override + public ContainerResponse filter(ContainerRequest cres, ContainerResponse response) { + initLazily(servletRequest); + String requestOrigin = cres.getHeaderValue("Origin"); + if (requestOrigin != null) { // is this is a cors request (ajax request that targets a different domain than the one the page was loaded from) + if (allowedOrigin != null && allowedOrigin.startsWith(requestOrigin)) { // no cors allowances make are applied if allowedOrigins == null + // only return the origin the client informed + response.getHttpHeaders().add("Access-Control-Allow-Origin", requestOrigin); + response.getHttpHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); + response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true"); + response.getHttpHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); + response.getHttpHeaders().add("Access-Control-Max-Age", "1209600"); + } + } + return response; + } + + private void initLazily(ServletRequest request) { + if (lazyServletContext == null) { + ServletContext context = request.getServletContext(); + String rootPath = context.getRealPath("/"); + rootPath = StringUtils.stripEnd(rootPath,"/"); // remove trailing "/" character + String restcommXmlPath = rootPath + "/WEB-INF/conf/restcomm.xml"; + + // ok, found restcomm.xml. Now let's get rcmlserver/base-url configuration setting + File restcommXmlFile = new File(restcommXmlPath); + // Create apache configuration + XMLConfiguration apacheConf = new XMLConfiguration(); + apacheConf.setDelimiterParsingDisabled(true); + apacheConf.setAttributeSplittingDisabled(true); + try { + apacheConf.load(restcommXmlPath); + } catch (ConfigurationException e) { + e.printStackTrace(); + } + // Create high-level configuration + ConfigurationSource source = new ApacheConfigurationSource(apacheConf); + RcmlserverConfigurationSet rcmlserverConfig = new RcmlserverConfigurationSetImpl(source); + // initialize allowedOrigin + String baseUrl = rcmlserverConfig.getBaseUrl(); + if ( baseUrl != null && (! baseUrl.trim().equals(""))) { + // baseUrl is set. We need to return CORS allow headers + allowedOrigin = baseUrl; + } + + lazyServletContext = context; + + logger.info("Initialized (lazily) CORS servlet response filter. allowedOrigin: " + allowedOrigin); + } + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/CustomReasonPhraseType.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/CustomReasonPhraseType.java new file mode 100644 index 0000000000..5d271ae5c6 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/CustomReasonPhraseType.java @@ -0,0 +1,60 @@ +/* + * 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.exceptionmappers; + +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.Response.Status.Family; +import javax.ws.rs.core.Response.StatusType; + +public class CustomReasonPhraseType implements StatusType { + + public CustomReasonPhraseType(final Family family, final int statusCode, + final String reasonPhrase) { + + this.family = family; + this.statusCode = statusCode; + this.reasonPhrase = reasonPhrase; + } + + public CustomReasonPhraseType(final Status status, + final String reasonPhrase) { + this(status.getFamily(), status.getStatusCode(), reasonPhrase); + } + + @Override + public Family getFamily() { + return family; + } + + @Override + public String getReasonPhrase() { + return reasonPhrase; + } + + @Override + public int getStatusCode() { + return statusCode; + } + + private final Family family; + private final int statusCode; + private final String reasonPhrase; + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/RestcommRuntimeExceptionMapper.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/RestcommRuntimeExceptionMapper.java new file mode 100644 index 0000000000..5ea76d4920 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptionmappers/RestcommRuntimeExceptionMapper.java @@ -0,0 +1,81 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptionmappers; + +import java.util.HashMap; +import java.util.Map; +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; +import org.restcomm.connect.http.exceptions.InsufficientPermission; +import org.restcomm.connect.http.exceptions.NotAuthenticated; +import org.restcomm.connect.http.exceptions.OperatedAccountMissing; +import org.restcomm.connect.http.exceptions.ResourceAccountMissmatch; +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * Generates 401 for AuthorizationException instead of a 500 (and an exception + * to the log). It helps to handle authorization errors when they occur in + * *Endpoint.init() method where there is no explicit way of returning a + * response (feature was needed after shiro removal). + * + * @author Orestis Tsakiridis + */ +@Provider +public class RestcommRuntimeExceptionMapper implements ExceptionMapper { + + static final Logger logger = Logger.getLogger(RestcommRuntimeExceptionMapper.class.getName()); + static final Map exceptionMap = new HashMap(); + + static { + exceptionMap.put(NotAuthenticated.class, + Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic realm=\"Restcomm realm\"").build()); + exceptionMap.put(InsufficientPermission.class, + Response.status(Response.Status.FORBIDDEN).build()); + exceptionMap.put(OperatedAccountMissing.class, + Response.status(Response.Status.NOT_FOUND).build()); + exceptionMap.put(ResourceAccountMissmatch.class, + Response.status(Response.Status.BAD_REQUEST).build()); + exceptionMap.put(AccountHierarchyDepthCrossed.class, + Response.status(Response.Status.INTERNAL_SERVER_ERROR).build()); + exceptionMap.put(NotAuthenticated.class, + Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic realm=\"Restcomm realm\"").build()); + + } + + @Override + public Response toResponse(RestcommRuntimeException e) { + if (logger.isDebugEnabled()) { + logger.debug("Converting response to a corresponding http status."); + } + Response res = null; + + if (exceptionMap.containsKey(e.getClass())) { + res = exceptionMap.get(e.getClass()); + } else { + // map all other types of auth errors to 403 + res = Response.status(Response.Status.FORBIDDEN).build(); + } + return res; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AccountAlreadyClosed.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AccountAlreadyClosed.java new file mode 100644 index 0000000000..dcd3c70ee6 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AccountAlreadyClosed.java @@ -0,0 +1,30 @@ +/* + * 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.exceptions; + +/** + * When an operation on an Account fails because the account is in CLOSED state throw + * this exception. + * + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public class AccountAlreadyClosed extends Exception { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AuthorizationException.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AuthorizationException.java new file mode 100644 index 0000000000..eb3a73f4a0 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/AuthorizationException.java @@ -0,0 +1,32 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptions; + +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + +/** + * General type of authorization exceptions. All security-related exceptions + * in REST endpoints should extend this. + * + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ + +public class AuthorizationException extends RestcommRuntimeException { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/EmailAlreadyExisted.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/EmailAlreadyExisted.java new file mode 100644 index 0000000000..833513a270 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/EmailAlreadyExisted.java @@ -0,0 +1,30 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptions; + +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + + +/** + * @author ddh.huy@gmail.com (Huy Dang) + */ +public class EmailAlreadyExisted extends RestcommRuntimeException { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InsufficientPermission.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InsufficientPermission.java new file mode 100644 index 0000000000..ba18a776ad --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InsufficientPermission.java @@ -0,0 +1,27 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptions; + +/** + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ +public class InsufficientPermission extends AuthorizationException { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InvalidEmailException.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InvalidEmailException.java new file mode 100644 index 0000000000..8eebb631d7 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/InvalidEmailException.java @@ -0,0 +1,35 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptions; + + +/** + * @author ddh.huy@gmail.com (Huy Dang) + */ +public class InvalidEmailException extends Exception { + //Parameterless Constructor + public InvalidEmailException() {} + + //Constructor that accepts a message + public InvalidEmailException(String message) { + super(message); + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/NotAuthenticated.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/NotAuthenticated.java new file mode 100644 index 0000000000..024e890162 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/NotAuthenticated.java @@ -0,0 +1,27 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.exceptions; + +/** + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ +public class NotAuthenticated extends AuthorizationException { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/OperatedAccountMissing.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/OperatedAccountMissing.java new file mode 100644 index 0000000000..6aef891779 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/OperatedAccountMissing.java @@ -0,0 +1,48 @@ +/* + * 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.exceptions; + +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class OperatedAccountMissing extends RestcommRuntimeException { + + public OperatedAccountMissing() { + } + + public OperatedAccountMissing(String message) { + super(message); + } + + public OperatedAccountMissing(String message, Throwable cause) { + super(message, cause); + } + + public OperatedAccountMissing(Throwable cause) { + super(cause); + } + + public OperatedAccountMissing(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/PasswordTooWeak.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/PasswordTooWeak.java new file mode 100644 index 0000000000..aa8d53d43f --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/PasswordTooWeak.java @@ -0,0 +1,9 @@ +package org.restcomm.connect.http.exceptions; + +/** + * Thrown when trying to persist a password that is too weak. + * + * @author otsakir@gmai.com - Orestis Tsakiridis + */ +public class PasswordTooWeak extends Exception { +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/RcmlserverNotifyError.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/RcmlserverNotifyError.java new file mode 100644 index 0000000000..00724f410c --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/RcmlserverNotifyError.java @@ -0,0 +1,41 @@ +/* + * 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.exceptions; + +/** + * Thrown when notification submission to rcmlserver failed for some reason. + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class RcmlserverNotifyError extends Exception { + + public RcmlserverNotifyError(String message) { + super(message); + } + + public RcmlserverNotifyError() { + } + + public RcmlserverNotifyError(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/ResourceAccountMissmatch.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/ResourceAccountMissmatch.java new file mode 100644 index 0000000000..52c95845bf --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/exceptions/ResourceAccountMissmatch.java @@ -0,0 +1,56 @@ +/* + * 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.exceptions; + +import org.restcomm.connect.commons.exceptions.RestcommRuntimeException; + +/** + * Thrown when a resource (like Clients, Numbers etc.) is accessed under an account + * that does not own them. + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class ResourceAccountMissmatch extends RestcommRuntimeException { + + public ResourceAccountMissmatch() { + } + + public ResourceAccountMissmatch(String message) { + super(message); + } + + public ResourceAccountMissmatch(String message, Throwable cause) { + super(message, cause); + } + + public ResourceAccountMissmatch(Throwable cause) { + super(cause); + } + + public ResourceAccountMissmatch(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + + + + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/BodyLengthFilter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/BodyLengthFilter.java new file mode 100644 index 0000000000..3e099139bc --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/BodyLengthFilter.java @@ -0,0 +1,57 @@ +/* + * 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.filters; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import static javax.ws.rs.core.Response.status; +import javax.ws.rs.ext.Provider; +import org.apache.log4j.Logger; +import org.restcomm.connect.http.exceptionmappers.CustomReasonPhraseType; + + + +@Provider +public class BodyLengthFilter implements ContainerRequestFilter { + protected Logger logger = Logger.getLogger(ExtensionFilter.class); + + private static final int MAX_REQ_BODY_SIZE = 10000000; + + @Override + public ContainerRequest filter(ContainerRequest request) { + String length = request.getHeaderValue(HttpHeaders.CONTENT_LENGTH); + if (length != null) { + int bodySize = Integer.parseInt(length); + if (bodySize > MAX_REQ_BODY_SIZE) { + logger.debug("Request rejected by size"); + CustomReasonPhraseType customReasonPhraseType = new CustomReasonPhraseType(Status.Family.CLIENT_ERROR, 413, "Length larger than " + MAX_REQ_BODY_SIZE); + Response build = status(customReasonPhraseType).build(); + throw new WebApplicationException(build); + } + } + + return request; + } +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/ExtensionFilter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/ExtensionFilter.java new file mode 100644 index 0000000000..6b046cd3ff --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/filters/ExtensionFilter.java @@ -0,0 +1,152 @@ +/* + * 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.filters; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; +import com.sun.jersey.spi.container.ContainerResponse; +import com.sun.jersey.spi.container.ContainerResponseFilter; +import com.sun.jersey.spi.container.ResourceFilter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import static javax.ws.rs.core.Response.Status.FORBIDDEN; +import static javax.ws.rs.core.Response.status; +import javax.ws.rs.ext.Provider; +import org.apache.log4j.Logger; +import org.restcomm.connect.extension.api.ApiRequest; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.http.exceptionmappers.CustomReasonPhraseType; + +/** + * Checks if this REST API request is allowed by Extensions. + * + * @author + */ +@Provider +public class ExtensionFilter implements ResourceFilter, ContainerRequestFilter, ContainerResponseFilter { + + protected Logger logger = Logger.getLogger(ExtensionFilter.class); + + private static final Map TYPE_MAP = new HashMap(); + + static { + TYPE_MAP.put("AvailablePhoneNumbers", ApiRequest.Type.AVAILABLEPHONENUMBER); + TYPE_MAP.put("IncomingPhoneNumbers", ApiRequest.Type.INCOMINGPHONENUMBER); + TYPE_MAP.put("AvailablePhoneNumbers.json", ApiRequest.Type.AVAILABLEPHONENUMBER); + TYPE_MAP.put("IncomingPhoneNumbers.json", ApiRequest.Type.INCOMINGPHONENUMBER); + } + + + private int retrieveAccountPathPosition(ContainerRequest cr) { + boolean accountFound = false; + int i = 0; + List pathSegments = cr.getPathSegments(); + while (i < pathSegments.size() && !accountFound) { + if (pathSegments.get(i).getPath().startsWith("Accounts")) { + accountFound = true; + } + } + if (accountFound && i + 1 < pathSegments.size()) { + //next path to "Accounts" + i = i + 1; + } else { + i = -1; + } + return i; + } + + private String retrieveAccountSid(ContainerRequest cr) { + String accountSid = null; + List pathSegments = cr.getPathSegments(); + int accountPos = retrieveAccountPathPosition(cr); + if (accountPos >= 0) { + accountSid = pathSegments.get(accountPos).getPath(); + } + return accountSid; + } + + private ApiRequest.Type mapType(ContainerRequest cr) { + ApiRequest.Type type = null; + List pathSegments = cr.getPathSegments(); + int accountPos = retrieveAccountPathPosition(cr); + if (accountPos >= 0 && accountPos + 1 < pathSegments.size()) { + String subResPath = pathSegments.get(accountPos + 1).getPath(); + type = TYPE_MAP.get(subResPath); + } + return type; + } + + @Override + public ContainerRequest filter(ContainerRequest cr) { + final String accountSid = retrieveAccountSid(cr); + ApiRequest.Type type = mapType(cr); + final MultivaluedMap data = cr.getFormParameters(); + if (accountSid != null && type != null) { + ApiRequest apiRequest = new ApiRequest(accountSid, data, type); + if (!executePreApiAction(apiRequest)) { + CustomReasonPhraseType customReasonPhraseType = new CustomReasonPhraseType(FORBIDDEN, "Extension blocked access"); + Response build = status(customReasonPhraseType).build(); + throw new WebApplicationException(build); + } + } + + return cr; + } + + @Override + public ContainerRequestFilter getRequestFilter() { + return this; + } + + @Override + public ContainerResponseFilter getResponseFilter() { + return this; + } + + private boolean executePreApiAction(final ApiRequest apiRequest) { + List extensions = ExtensionController.getInstance().getExtensions(ExtensionType.RestApi); + ExtensionController ec = ExtensionController.getInstance(); + return ec.executePreApiAction(apiRequest, extensions).isAllowed(); + } + + private boolean executePostApiAction(final ApiRequest apiRequest) { + List extensions = ExtensionController.getInstance().getExtensions(ExtensionType.RestApi); + ExtensionController ec = ExtensionController.getInstance(); + return ec.executePostApiAction(apiRequest, extensions).isAllowed(); + } + + @Override + public ContainerResponse filter(ContainerRequest cr, ContainerResponse response) { + final String accountSid = retrieveAccountSid(cr); + ApiRequest.Type type = mapType(cr); + final MultivaluedMap data = cr.getFormParameters(); + ApiRequest apiRequest = new ApiRequest(accountSid, data, type); + executePostApiAction(apiRequest); + return response; + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/AccountPrincipal.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/AccountPrincipal.java new file mode 100644 index 0000000000..4b6a598cf4 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/AccountPrincipal.java @@ -0,0 +1,63 @@ +/* + * 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.security; + +import java.security.Principal; +import java.util.Set; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.identity.UserIdentityContext; + +public class AccountPrincipal implements Principal { + public static final String SUPER_ADMIN_ROLE = "SuperAdmin"; + public static final String ADMIN_ROLE = "Administrator"; + + UserIdentityContext identityContext; + + public AccountPrincipal(UserIdentityContext identityContext) { + this.identityContext = identityContext; + } + + protected boolean isSuperAdmin() { + //SuperAdmin Account is the one the is + //1. Has no parent, this is the top account + //2. Is ACTIVE + return (identityContext.getEffectiveAccount() != null + && identityContext.getEffectiveAccount().getParentSid() == null) + && (identityContext.getEffectiveAccount().getStatus().equals(Account.Status.ACTIVE)); + } + + public Set getRole() { + Set roles = identityContext.getEffectiveAccountRoles(); + if (isSuperAdmin()) { + roles.add(SUPER_ADMIN_ROLE); + } + return roles; + } + + @Override + public String getName() { + if (identityContext.getEffectiveAccount() != null) { + return identityContext.getAccountKey().getAccount().getSid().toString(); + } else { + return null; + } + } + +} diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/RCSecContext.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/RCSecContext.java new file mode 100644 index 0000000000..45988cf2ad --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/RCSecContext.java @@ -0,0 +1,55 @@ + +/* + * 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.security; + +import javax.ws.rs.core.SecurityContext; +import java.security.Principal; + +public class RCSecContext implements SecurityContext{ + private AccountPrincipal user; + private String scheme; + + public RCSecContext(AccountPrincipal user, String scheme) { + this.user = user; + this.scheme = scheme; + } + + @Override + public Principal getUserPrincipal() {return this.user;} + + @Override + public boolean isUserInRole(String s) { + if (user.getRole() != null) { + return user.getRole().contains(s); + } + return false; + } + + @Override + public boolean isSecure() {return "https".equals(this.scheme);} + + @Override + public String getAuthenticationScheme() { + return SecurityContext.BASIC_AUTH; + } +} + diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/SecurityFilter.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/SecurityFilter.java new file mode 100644 index 0000000000..4b9fbe3905 --- /dev/null +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/security/SecurityFilter.java @@ -0,0 +1,91 @@ +/* + * 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.security; + +import static javax.ws.rs.core.Response.status; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.Provider; + +import org.apache.log4j.Logger; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.identity.UserIdentityContext; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; + +@Provider +public class SecurityFilter implements ContainerRequestFilter { + + private final Logger logger = Logger.getLogger(SecurityFilter.class); + private static final String PATTERN_FOR_RECORDING_FILE_PATH=".*Accounts/.*/Recordings/RE.*[.mp4|.wav]"; + private static final String PATTERN_FOR_LOGOUT_PATH=".*Logout$"; + + @Context + private HttpServletRequest servletRequest; + + // We return Access-* headers only in case allowedOrigin is present and equals to the 'Origin' header. + @Override + public ContainerRequest filter(ContainerRequest cr) { + final DaoManager storage = (DaoManager) servletRequest.getServletContext().getAttribute(DaoManager.class.getName()); + AccountsDao accountsDao = storage.getAccountsDao(); + UserIdentityContext userIdentityContext = new UserIdentityContext(servletRequest, accountsDao); + // exclude recording file https://telestax.atlassian.net/browse/RESTCOMM-1736 + logger.info("cr.getPath(): "+cr.getPath()); + final boolean isRecordingsPath = cr.getPath().matches(PATTERN_FOR_RECORDING_FILE_PATH); + final boolean isLogoutPath = cr.getPath().matches(PATTERN_FOR_LOGOUT_PATH); + if (!isRecordingsPath && !isLogoutPath) { + checkAuthenticatedAccount(userIdentityContext); + filterClosedAccounts(userIdentityContext, cr.getPath()); + } + String scheme = cr.getAuthenticationScheme(); + AccountPrincipal aPrincipal = new AccountPrincipal(userIdentityContext); + cr.setSecurityContext(new RCSecContext(aPrincipal, scheme)); + return cr; + } + + /** + * Grants general purpose access if any valid token exists in the request + */ + protected void checkAuthenticatedAccount(UserIdentityContext userIdentityContext) { + if (userIdentityContext.getEffectiveAccount() == null) { + throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic realm=\"Restcomm realm\"").build()); + } + } + + /** + * filter out accounts that are not active + * @param userIdentityContext + */ + protected void filterClosedAccounts(UserIdentityContext userIdentityContext, String path){ + if(userIdentityContext.getEffectiveAccount() != null && !userIdentityContext.getEffectiveAccount().getStatus().equals(Account.Status.ACTIVE)){ + if (userIdentityContext.getEffectiveAccount().getStatus().equals(Account.Status.UNINITIALIZED) && path.startsWith("Accounts")) { + return; + } + throw new WebApplicationException(status(Status.FORBIDDEN).entity("Provided Account is not active").build()); + } + } +} diff --git a/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-feature-enablement-schema.json b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-feature-enablement-schema.json new file mode 100644 index 0000000000..798e167f89 --- /dev/null +++ b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-feature-enablement-schema.json @@ -0,0 +1,134 @@ +{ + "type": "object", + "id": "#rc-fac-extension-schema.json", + "definitions": { + "featureEnablement": { + "type": "object", + "additionalProperties": false, + "properties": { + "DIDPurchase": { + "type": "object", + "additionalProperties": false, + "properties": { + "allowedCountries": { + "type": "array", + "additionalItems": false, + "description": "ISO_3166-1 alpha2 country codes", + "items": { + "type": "string", + "pattern": "^[A-Z][A-Z]$" + + } + } + } + + }, + "subaccountsCreation": { + "type": "object", + "additionalProperties": false, + "properties": { + "limit": { + "type": "integer" + + } + } + }, + "outboundPSTN": { + "type": "object", + "additionalProperties": false, + "properties": { + "allowedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + }, + "blockedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + } + } + }, + "inboundPSTN": { + "type": "object", + "additionalProperties": false + }, + "outboundSMS": { + "type": "object", + "additionalProperties": false, + "properties": { + "allowedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + }, + "blockedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + } + } + }, + "inboundSMS": { + "type": "object", + "additionalProperties": false + }, + "asr": { + "type": "object", + "additionalProperties": false + }, + "USSD": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "type": "string", + "enum": ["default", "virgin", "somos"] + } + } + }, + "inboundUSSD": { + "type": "object", + "additionalProperties": false + }, + "outboundUSSD": { + "type": "object", + "additionalProperties": false, + "properties": { + "allowedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + }, + "blockedPrefixes": { + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + + } + } + } + } + } + } + + }, + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-profile-schema.json b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-profile-schema.json new file mode 100644 index 0000000000..632d4ac548 --- /dev/null +++ b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-profile-schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "resource:/org/restcomm/connect/http/schemas/rc-profile-schema.json#", + "additionalProperties": false, + "type": "object", + "properties": { + "featureEnablement": { + "$ref": "rc-feature-enablement-schema.json#/definitions/featureEnablement" + }, + "sessionThrottling": { + "$ref": "rc-session-throttling-schema.json#/definitions/sessionThrottling" + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-session-throttling-schema.json b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-session-throttling-schema.json new file mode 100644 index 0000000000..cda28bea5f --- /dev/null +++ b/restcomm/restcomm.http/src/main/resources/org/restcomm/connect/http/schemas/rc-session-throttling-schema.json @@ -0,0 +1,70 @@ +{ + "type": "object", + "id": "#rc-session-throttling-schema.json", + "definitions": { + "timeUnit":{ + "type": "string", + "enum": ["nanoseconds","milliseconds","seconds","minutes","hours","days","weeks","months","years"], + "description" :"TODO investigate time types RFC3339" + }, + "eventsPerTimeRule": { + "type": "object", + "additionalProperties": false, + "properties": { + "events": { + "type": "integer" + + }, + "time": { + "type": "integer" + + }, + "timeUnit": { + "$ref": "#/definitions/timeUnit" + } + }, + "required": ["events", "time", "timeUnit"] + }, + "maxEventsPerTimeRule": { + "type": "object", + "additionalProperties": false, + "properties": { + "events": { + "type": "integer" + + }, + "time": { + "type": "integer" + + }, + "timeUnit": { + "$ref": "#/definitions/timeUnit" + } + }, + "required": ["events", "time", "timeUnit"] + }, + "maxEventsSimultaneouslyRule": { + "type": "object", + "additionalProperties": false, + "properties": { + "events": { + "type": "integer" + } + } + , + "required": ["events"] + }, + "sessionThrottling": { + "type": "object", + "additionalProperties": false, + "properties": { + "PSTNCallsPerTime": { + "$ref": "#/definitions/maxEventsPerTimeRule" + } + } + } + + }, + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/java/org/mobicents/servlet/restcomm/http/client/DownloaderTest.java b/restcomm/restcomm.http/src/test/java/org/mobicents/servlet/restcomm/http/client/DownloaderTest.java deleted file mode 100644 index b79a45966a..0000000000 --- a/restcomm/restcomm.http/src/test/java/org/mobicents/servlet/restcomm/http/client/DownloaderTest.java +++ /dev/null @@ -1,117 +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.mobicents.servlet.restcomm.http.client; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.testkit.JavaTestKit; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.concurrent.TimeUnit; - -import org.junit.After; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import scala.concurrent.duration.FiniteDuration; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class DownloaderTest { - private ActorSystem system; - private ActorRef downloader; - - public DownloaderTest() { - super(); - } - - @Before - public void before() throws Exception { - system = ActorSystem.create(); - downloader = system.actorOf(new Props(Downloader.class)); - } - - @After - public void after() throws Exception { - system.shutdown(); - } - - @Test - public void testGet() throws URISyntaxException, IOException { - new JavaTestKit(system) { - { - final ActorRef observer = getRef(); - final URI uri = URI.create("http://www.restcomm.org"); - final String method = "GET"; - final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); - downloader.tell(request, observer); - final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); - final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); - assertTrue(response.succeeded()); - final HttpResponseDescriptor descriptor = response.get(); - System.out.println("Result: " + descriptor.getContentAsString()); - assertTrue(descriptor.getContentAsString().contains("RestComm - Home")); - } - }; - } - - @Test - @Ignore - public void testPost() throws URISyntaxException, IOException { - new JavaTestKit(system) { - { - final ActorRef observer = getRef(); - final URI uri = URI.create("http://www.restcomm.org"); - final String method = "POST"; - final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); - downloader.tell(request, observer); - final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); - final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); - assertTrue(response.succeeded()); - final HttpResponseDescriptor descriptor = response.get(); - assertTrue(descriptor.getContentAsString().contains("RestComm - Home")); - } - }; - } - - @Test - public void testNotFound() throws URISyntaxException, IOException { - new JavaTestKit(system) { - { - final ActorRef observer = getRef(); - final URI uri = URI.create("http://www.telestax.com/not-found.html"); - final String method = "GET"; - final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); - downloader.tell(request, observer); - final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); - final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); - assertTrue(response.succeeded()); - final HttpResponseDescriptor descriptor = response.get(); - assertTrue(descriptor.getStatusCode() == 404); - } - }; - } -} diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/AccountsEndpointMockedTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/AccountsEndpointMockedTest.java new file mode 100644 index 0000000000..8d8edd19d6 --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/AccountsEndpointMockedTest.java @@ -0,0 +1,70 @@ +/* + * 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; + +import com.sun.jersey.core.util.MultivaluedMapImpl; +import java.net.URI; +import java.net.URISyntaxException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.commons.configuration.ConfigurationException; +import org.joda.time.DateTime; +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Account; +import org.restcomm.connect.dao.entities.Organization; + +/** + * A sample unit test for accounts endpoint. It illustrates the use of the EndpointMockedTest. + * + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public class AccountsEndpointMockedTest extends EndpointMockedTest { + @Test + public void endpointInitializedAndBasicAuthorizationWork() throws ConfigurationException, URISyntaxException { + init(); // setup default mocking values + AccountsEndpoint endpoint = new AccountsEndpoint(servletContext,request); + endpoint.init(); + } + + @Test + public void statusUpdate() throws ConfigurationException, URISyntaxException { + init(); // setup default mocking values + Account account = new Account(new Sid("AC00000000000000000000000000000000"),new DateTime(),new DateTime(),"administrator@company.com","Administrator",new Sid("AC00000000000000000000000000000001"),Account.Type.TRIAL,Account.Status.ACTIVE,"77f8c12cc7b8f8423e5c38b035249166","Administrator",new URI("/uri"), Sid.generate(Sid.Type.ORGANIZATION)); + Organization organization = new Organization(account.getOrganizationSid(), "domainName", null, null, Organization.Status.ACTIVE); + when(accountsDao.getAccount(any(Sid.class))).thenReturn(account); + when(accountsDao.getAccount(any(String.class))).thenReturn(account); + when(accountsDao.getAccountToAuthenticate(any(String.class))).thenReturn(account); + when(orgDao.getOrganization(any(Sid.class))).thenReturn(organization); + + + AccountsEndpoint endpoint = new AccountsEndpoint(servletContext,request); + endpoint.init(); + MultivaluedMapImpl multivaluedMapImpl = new MultivaluedMapImpl(); + multivaluedMapImpl.putSingle("Status", "active"); + Response updateAccount = endpoint.updateAccount(account.getSid().toString(), multivaluedMapImpl, MediaType.APPLICATION_JSON_TYPE); + assertEquals(200, updateAccount.getStatus()); + } + +} diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/EndpointMockedTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/EndpointMockedTest.java new file mode 100644 index 0000000000..fe42ed93e3 --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/EndpointMockedTest.java @@ -0,0 +1,103 @@ +/* + * 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; + +import java.net.URISyntaxException; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.Account; +import org.mockito.Mockito; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +import static org.mockito.Mockito.when; +import org.restcomm.connect.dao.ClientsDao; +import org.restcomm.connect.dao.OrganizationsDao; +import org.restcomm.connect.identity.IdentityContext; + +/** + * Base class for unit testing restcomm endpoints by mocking the following dependent components: + * + * - Configuration + * - DaoManager and individual daos + * - ServletContext + * - HttpServletRequest + * + * Extend this class and further customize it to test other endpoints. See sample AccountsEndpointMockedTest + * to get an idea how this works. + * + * @author orestis.tsakiridis@telestax.com - Orestis Tsakiridis + */ +public class EndpointMockedTest { + + Configuration conf; + ServletContext servletContext; + List accounts; + AccountsDao accountsDao; + DaoManager daoManager; + HttpServletRequest request; + OrganizationsDao orgDao; + ClientsDao clientsDao; + + + void init() throws URISyntaxException { + String restcommXmlPath = AccountsEndpointMockedTest.class.getResource("/restcomm.xml").getFile(); + try { + conf = getConfiguration(restcommXmlPath, "/restcomm", "http://localhost:8080"); + } catch (ConfigurationException e) { + throw new RuntimeException(); + } + // create ServletContext mock + servletContext = Mockito.mock(ServletContext.class); + daoManager = Mockito.mock(DaoManager.class); + accountsDao = Mockito.mock(AccountsDao.class); + orgDao= Mockito.mock(OrganizationsDao.class); + clientsDao= Mockito.mock(ClientsDao.class); + when(servletContext.getAttribute(Configuration.class.getName())).thenReturn(conf); + when(daoManager.getAccountsDao()).thenReturn(accountsDao); + when(daoManager.getOrganizationsDao()).thenReturn(orgDao); + when(daoManager.getClientsDao()).thenReturn(clientsDao); + when(servletContext.getAttribute(DaoManager.class.getName())).thenReturn(daoManager); + when(servletContext.getAttribute(IdentityContext.class.getName())).thenReturn(new IdentityContext(conf)); + // createt request mock + request = Mockito.mock(HttpServletRequest.class); + when(request.getHeader("Authorization")).thenReturn("Basic YWRtaW5pc3RyYXRvckBjb21wYW55LmNvbTo3N2Y4YzEyY2M3YjhmODQyM2U1YzM4YjAzNTI0OTE2Ng=="); + } + + private Configuration getConfiguration(String path, String homeDirectory, String rootUri) throws ConfigurationException { + Configuration xml = null; + + XMLConfiguration xmlConfiguration = new XMLConfiguration(); + xmlConfiguration.setDelimiterParsingDisabled(true); + xmlConfiguration.setAttributeSplittingDisabled(true); + xmlConfiguration.load(path); + xml = xmlConfiguration; + xml.setProperty("runtime-settings.home-directory", homeDirectory); + xml.setProperty("runtime-settings.root-uri", rootUri); + return xml; + } + +} diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/DownloaderTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/DownloaderTest.java new file mode 100644 index 0000000000..d0241cac4a --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/DownloaderTest.java @@ -0,0 +1,192 @@ +/* + * 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; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.JavaTestKit; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import com.github.tomakehurst.wiremock.junit.WireMockRule; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.concurrent.TimeUnit; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.http.conn.ConnectionPoolTimeoutException; + +import org.junit.After; +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; + +import scala.concurrent.duration.FiniteDuration; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +public final class DownloaderTest { + + private ActorSystem system; + private ActorRef downloader; + + private static int MOCK_PORT = 8099; + //use localhost instead of 127.0.0.1 to match the route rule + private static String PATH = "http://localhost:" + MOCK_PORT + "/"; + + @Rule + public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().bindAddress("127.0.0.1").port(MOCK_PORT)); + + public DownloaderTest() { + super(); + } + + @Before + public void before() throws Exception { + URL url = this.getClass().getResource("/restcomm.xml"); + Configuration xml = new XMLConfiguration(url); + RestcommConfiguration.createOnce(xml); + system = ActorSystem.create(); + downloader = system.actorOf(new Props(Downloader.class)); + } + + @After + public void after() throws Exception { + system.shutdown(); + wireMockRule.resetRequests(); + } + + @Test + public void testGet() throws URISyntaxException, IOException { + stubFor(get(urlMatching("/testGet")).willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("expectedBody"))); + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final URI uri = URI.create(PATH + "testGet"); + final String method = "GET"; + final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); + downloader.tell(request, observer); + final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); + final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); + assertTrue(response.succeeded()); + final HttpResponseDescriptor descriptor = response.get(); + System.out.println("Result: " + descriptor.getContentAsString()); + assertTrue(descriptor.getContentAsString().contains("expectedBody")); + } + }; + } + + @Test + @Ignore + public void testPost() throws URISyntaxException, IOException { + stubFor(post(urlMatching("/testPost")).willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("expectedBody"))); + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final URI uri = URI.create(PATH + "testPost"); + final String method = "POST"; + final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); + downloader.tell(request, observer); + final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); + final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); + assertTrue(response.succeeded()); + final HttpResponseDescriptor descriptor = response.get(); + assertTrue(descriptor.getContentAsString().contains("expectedBody")); + } + }; + } + + @Test + public void testNotFound() throws URISyntaxException, IOException { + stubFor(get(urlMatching("/testNotFound")).willReturn(aResponse() + .withStatus(404) + .withHeader("Content-Type", "application/json") + .withBody("{}"))); + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final URI uri = URI.create(PATH + "testNotFound"); + final String method = "GET"; + final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); + downloader.tell(request, observer); + final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); + final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); + assertTrue(response.succeeded()); + final HttpResponseDescriptor descriptor = response.get(); + assertEquals(404, descriptor.getStatusCode()); + } + }; + } + + + /** + * configuration comes from restcomm.xml file + * + * @throws Exception + */ + @Test() + public void testDownloaderWithRouteconfiguration() throws Exception { + stubFor(get(urlMatching("/testDownloaderWithRouteconfiguration")).willReturn(aResponse() + .withFixedDelay(5000 * 2)//delay will cause read timeout to happen + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("{}"))); + new JavaTestKit(system) { + { + int connsPerRoute = 5; + final URI uri = URI.create(PATH + "testDownloaderWithRouteconfiguration"); + final String method = "GET"; + final HttpRequestDescriptor request = new HttpRequestDescriptor(uri, method); + final ActorRef observer = getRef(); + + for (int i =0; i < connsPerRoute; i ++) + { + downloader = system.actorOf(new Props(Downloader.class)); + downloader.tell(request, observer); + } + Thread.sleep(1000); + downloader = system.actorOf(new Props(Downloader.class)); + downloader.tell(request, observer); + final FiniteDuration timeout = FiniteDuration.create(30, TimeUnit.SECONDS); + final DownloaderResponse response = expectMsgClass(timeout, DownloaderResponse.class); + assertFalse(response.succeeded()); + //JavaTestKit dont allow to throw exception and use "expected" + assertEquals(ConnectionPoolTimeoutException.class, response.cause().getClass()); + } + }; + } +} diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/api/ApiClientTests.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/api/ApiClientTests.java new file mode 100644 index 0000000000..1e5b9e7727 --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/api/ApiClientTests.java @@ -0,0 +1,163 @@ +/* + * 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.api; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.XMLConfiguration; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.http.client.CallApiResponse; +import org.restcomm.connect.telephony.api.Hangup; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.ReceiveTimeout; +import akka.actor.UntypedActor; +import akka.actor.UntypedActorFactory; +import akka.testkit.JavaTestKit; +import scala.concurrent.duration.FiniteDuration; + +/** + * @author maria.farooq + */ +public final class ApiClientTests { + + private ActorSystem system; + + private static int MOCK_PORT = 8099; + private static final Sid TEST_CALL_SID = new Sid("ID8deb35fc5121429fa96635aebe3976d2-CA6d61e3877f3c47828a26efc498a9e8f9"); + private static final String TEST_CALL_URI = "/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Calls/ID8deb35fc5121429fa96635aebe3976d2-CA6d61e3877f3c47828a26efc498a9e8f9"; + + @Rule + public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().bindAddress("127.0.0.1").port(MOCK_PORT)); + + public ApiClientTests() { + super(); + } + + @Before + public void before() throws Exception { + URL url = this.getClass().getResource("/restcomm.xml"); + Configuration xml = new XMLConfiguration(url); + RestcommConfiguration.createOnce(xml); + system = ActorSystem.create(); + } + + @After + public void after() throws Exception { + system.shutdown(); + wireMockRule.resetRequests(); + } + + private Props CallApiClientProps(final DaoManager storage){ + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new CallApiClient(null, storage); + } + }); + return props; + } + + @Test + public void testCallApiTimeoutTermination() throws URISyntaxException, IOException, InterruptedException { + stubFor(get(urlMatching("/testGet")).willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("expectedBody"))); + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + DaoManager daoManager = mock(DaoManager.class); + CallDetailRecord.Builder cdrBuilder = CallDetailRecord.builder(); + cdrBuilder.setSid(TEST_CALL_SID); + cdrBuilder.setUri(new URI(TEST_CALL_URI)); + CallDetailRecord cdr = cdrBuilder.build(); + CallDetailRecordsDao cdrDao = mock(CallDetailRecordsDao.class); + when(daoManager.getCallDetailRecordsDao()).thenReturn(cdrDao); + when(cdrDao.getCallDetailRecord(any(Sid.class))).thenReturn(cdr); + + ActorRef callApiClient = system.actorOf(CallApiClientProps(daoManager)); + callApiClient.tell(new ReceiveTimeout() {}, observer); + final FiniteDuration timeout = FiniteDuration.create(15, TimeUnit.SECONDS); + final CallApiResponse response = expectMsgClass(timeout, CallApiResponse.class); + assertFalse(response.succeeded()); + Thread.sleep(1000); + assertTrue(callApiClient.isTerminated()); + } + }; + } + + @Test + public void testCallApiClientFailedResponse() throws URISyntaxException, IOException, InterruptedException { + stubFor(get(urlMatching("/testGet")).willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("expectedBody"))); + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + DaoManager daoManager = mock(DaoManager.class); + CallDetailRecord.Builder cdrBuilder = CallDetailRecord.builder(); + cdrBuilder.setSid(TEST_CALL_SID); + cdrBuilder.setUri(new URI(TEST_CALL_URI)); + CallDetailRecord cdr = cdrBuilder.build(); + CallDetailRecordsDao cdrDao = mock(CallDetailRecordsDao.class); + when(daoManager.getCallDetailRecordsDao()).thenReturn(cdrDao); + when(cdrDao.getCallDetailRecord(any(Sid.class))).thenReturn(cdr); + + ActorRef callApiClient = system.actorOf(CallApiClientProps(daoManager)); + callApiClient.tell(new Hangup("test", new Sid("ACae6e420f425248d6a26948c17a9e2acf"), null), observer); + final FiniteDuration timeout = FiniteDuration.create(15, TimeUnit.SECONDS); + final CallApiResponse response = expectMsgClass(timeout, CallApiResponse.class); + assertFalse(response.succeeded()); + } + }; + } +} 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.http/src/test/java/org/restcomm/connect/http/converter/ApplicationConverterTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/converter/ApplicationConverterTest.java new file mode 100644 index 0000000000..40bed238ac --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/converter/ApplicationConverterTest.java @@ -0,0 +1,94 @@ +/* + * 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.converter; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thoughtworks.xstream.XStream; +import junit.framework.Assert; +import org.joda.time.DateTime; +import org.junit.Test; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Application; +import org.restcomm.connect.dao.entities.ApplicationNumberSummary; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class ApplicationConverterTest { + + @Test + public void testNestedNumbersProperty() throws URISyntaxException { + // Initialize Json and XML converters + final ApplicationConverter applicationConverter = new ApplicationConverter(null); + final GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Application.class, applicationConverter); + // convert camelCaseFieldNames to camel_case_field_names convention. This will only affect ApplicationNumberSummary + builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); + builder.setPrettyPrinting(); + Gson gson = builder.create(); + ApplicationNumberSummaryConverter numberConverter = new ApplicationNumberSummaryConverter(); + XStream xstream = new XStream(); + //xstream.alias("RestcommResponse", RestCommResponse.class); + xstream.registerConverter(applicationConverter); + xstream.registerConverter(numberConverter); + xstream.registerConverter(new ApplicationListConverter(null)); + xstream.alias("Number",ApplicationNumberSummary.class); + //xstream.alias("Numbers", ); + //xstream.registerConverter(new RestCommResponseConverter(configuration)); + + Application app = new Application( new Sid("AP73926e7113fa4d95981aa96b76eca854"), new DateTime(), new DateTime(), "test app", new Sid("ACae6e420f425248d6a26948c17a9e2acf"), "2012-04-24", false, new URI("/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Applications/AP73926e7113fa4d95981aa96b76eca854"),new URI("/restcomm-rvd/services/apps/AP73926e7113fa4d95981aa96b76eca854/controller"), Application.Kind.VOICE); + List numbers = new ArrayList(); + ApplicationNumberSummary numberSummary = new ApplicationNumberSummary( + "PN00000000000000000000000000000001", + "1234", + "+1234", + "AP73926e7113fa4d95981aa96b76eca854", null,null,null + ); + numbers.add(numberSummary); + numberSummary = new ApplicationNumberSummary( + "PN00000000000000000000000000000002", + "1234", + "+1234", + "AP73926e7113fa4d95981aa96b76eca854", null,null,null + ); + numbers.add(numberSummary); + app.setNumbers(numbers); + + List apps = new ArrayList(); + apps.add(app); + // test json results + String responseJson = gson.toJson(apps); + Assert.assertTrue(responseJson.contains("\"numbers\": [")); + Assert.assertTrue(responseJson.contains("\"phone_number\": \"+1234\"")); + // test xml results + String responseXML = xstream.toXML(app); + responseXML = responseXML.replaceAll("[ \n]",""); + Assert.assertTrue(responseXML.contains("")); + Assert.assertTrue(responseXML.contains("+1234")); + } +} diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/schemas/ProfileSchemaTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/schemas/ProfileSchemaTest.java new file mode 100644 index 0000000000..fab7687b13 --- /dev/null +++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/schemas/ProfileSchemaTest.java @@ -0,0 +1,117 @@ +package org.restcomm.connect.http.schemas; + +import org.junit.Test; + +/* + * 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 + * + */ +import com.fasterxml.jackson.core.JsonPointer; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchema; +import com.github.fge.jsonschema.main.JsonSchemaFactory; + +import junit.framework.Assert; + +import java.io.File; + +import static org.junit.Assert.assertTrue; + +/** + * + * @author + */ +public class ProfileSchemaTest { + + public ProfileSchemaTest() { + } + + @Test + public void testFreePlan() throws Exception { + final JsonNode fstabSchema = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/rc-profile-schema.json"); + final JsonNode good = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/freePlan.json"); + + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + + final JsonSchema schema = factory.getJsonSchema(fstabSchema); + + ProcessingReport report; + + report = schema.validate(good); + Assert.assertTrue(report.isSuccess()); + } + + @Test + public void testEmptyProfile() throws Exception { + final JsonNode fstabSchema = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/rc-profile-schema.json"); + final JsonNode good = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/emptyProfile.json"); + + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + + final JsonSchema schema = factory.getJsonSchema(fstabSchema); + + ProcessingReport report; + + report = schema.validate(good); + Assert.assertTrue(report.isSuccess()); + } + + @Test + public void testRetrieveAllowedPrefixes() throws Exception { + final JsonNode good = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/freePlan.json"); + JsonPointer pointer = JsonPointer.compile("/featureEnablement/outboundPSTN/allowedPrefixes"); + JsonNode at = good.at(pointer); + Assert.assertNotNull(at); + Assert.assertTrue(at.isArray()); + Assert.assertEquals("+1", at.get(0).asText()); + } + + @Test + public void testInvalidFeature() throws Exception { + final JsonNode fstabSchema = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/rc-profile-schema.json"); + final JsonNode good = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/invalidFeature.json"); + + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + + final JsonSchema schema = factory.getJsonSchema(fstabSchema); + + ProcessingReport report; + + report = schema.validate(good); + Assert.assertFalse(report.isSuccess()); + } + + @Test + public void testDefaultPlan() throws Exception { + final JsonNode fstabSchema = JsonLoader.fromResource("/org/restcomm/connect/http/schemas/rc-profile-schema.json"); + File defaultPlan = new File("../restcomm.application/src/main/webapp/WEB-INF/conf/defaultPlan.json"); + final JsonNode good = JsonLoader.fromFile(defaultPlan); + + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + + final JsonSchema schema = factory.getJsonSchema(fstabSchema); + + ProcessingReport report; + + report = schema.validate(good); + assertTrue(report.isSuccess()); + } + +} diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/emptyProfile.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/emptyProfile.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/emptyProfile.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/freePlan.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/freePlan.json new file mode 100644 index 0000000000..c0eb1fe217 --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/freePlan.json @@ -0,0 +1,26 @@ +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CA"] + }, + "outboundPSTN": { + "allowedPrefixes": ["+1"] + }, + "inboundPSTN": { + }, + "outboundSMS": { + "allowedPrefixes": ["+44"] + }, + "inboundSMS": { + } + + }, + "sessionThrottling": { + "PSTNCallsPerTime": { + "events" : 300, + "time" : 30, + "timeUnit" : "days" + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/invalidFeature.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/invalidFeature.json new file mode 100644 index 0000000000..bafd0fda3d --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/invalidFeature.json @@ -0,0 +1,8 @@ +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CAnada"] + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planA.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planA.json new file mode 100644 index 0000000000..0a4968b511 --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planA.json @@ -0,0 +1,24 @@ +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CA"] + }, + "outboundPSTN": { + }, + "inboundPSTN": { + }, + "outboundSMS": { + }, + "inboundSMS": { + } + + }, + "sessionThrottling": { + "PSTNCallsPerTime": { + "events" : 300, + "time" : 30, + "timeUnit" : "days" + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planB.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planB.json new file mode 100644 index 0000000000..9f9c2126b3 --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planB.json @@ -0,0 +1,24 @@ +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CA"] + }, + "outboundPSTN": { + }, + "inboundPSTN": { + }, + "outboundSMS": { + }, + "inboundSMS": { + } + + }, + "sessionThrottling": { + "PSTNCallsPerTime": { + "events" : 300, + "time" : 30, + "timeUnit" : "days" + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planC.json b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planC.json new file mode 100644 index 0000000000..9f9c2126b3 --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/org/restcomm/connect/http/schemas/planC.json @@ -0,0 +1,24 @@ +{ + "featureEnablement": { + "DIDPurchase": { + "allowedCountries": ["US", + "CA"] + }, + "outboundPSTN": { + }, + "inboundPSTN": { + }, + "outboundSMS": { + }, + "inboundSMS": { + } + + }, + "sessionThrottling": { + "PSTNCallsPerTime": { + "events" : 300, + "time" : 30, + "timeUnit" : "days" + } + } +} \ No newline at end of file diff --git a/restcomm/restcomm.http/src/test/resources/restcomm.xml b/restcomm/restcomm.http/src/test/resources/restcomm.xml new file mode 100644 index 0000000000..aeec52b858 --- /dev/null +++ b/restcomm/restcomm.http/src/test/resources/restcomm.xml @@ -0,0 +1,426 @@ + + + + + + + + 2012-04-24 + + + false + + + /restcomm/audio + + + ${restcomm:home}/cache + /restcomm/cache + + + file://${restcomm:home}/recordings + /restcomm/recordings + + + /restcomm/errors + + + + + + true + + + false + + + true + + + 60 + + + true + + true + + + + true + + + + + + 127.0.0.1:5070 + + + + + 127.0.0.1:5090 + + + + true + + + true + + + true + + 20 + + true + + + + false + restcomm + restcomm + restcomm_instance_id + http://127.0.0.1:2080 + + + + + 127.0.0.1:5090 + + + + + + + + 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:Read:Accounts + + + + + + + + + + + + + + + + + + https://backoffice.voipinnovations.com/api2.pl + + + + + + + + + + + + + + + + + + + + + + ${restcomm:home}/WEB-INF/conf/mybatis.xml + + ${restcomm:home}/WEB-INF/data/hsql + ${restcomm:home}/WEB-INF/sql + + + + false + restcomm-recordings + + + + false + 7 + true + + + + + mms + +
      127.0.0.1
      + 5060 + udp + 5 +
      +
      + + + + + 127.0.0.1 + 2727 + 127.0.0.1 + 2427 + 1500 + + + + + + + + + 5000 + + allowall + + true + + + 2000 + 200 + 2 + 30000 + + + + + + 127.0.0.1:5090 + + + + + + + + + test + test + 127.0.0.1 + 2776 + TRANSCEIVER + + test + sms + + 0x34 + -1 + -1 + + + 1 + + 60000 + + 10000 + + 30000 + + 15000 + true + true + + 30000 + + + + + + + + + + + + + + + + + + + http://api.voicerss.org + 16824850f3634b9eb8a464350c0b133d + + 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 + + + strict + + true + + + + pl-pl + pt-br + pt-pt + ru-ru + es-mx + es-es + sv-se + + + + + +
      diff --git a/restcomm/restcomm.identity/pom.xml b/restcomm/restcomm.identity/pom.xml new file mode 100644 index 0000000000..93bf5463d8 --- /dev/null +++ b/restcomm/restcomm.identity/pom.xml @@ -0,0 +1,89 @@ + + 4.0.0 + + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT + + + restcomm-connect.identity + restcomm-connect.identity + http://maven.apache.org + + + UTF-8 + + + + + + org.slf4j + slf4j-api + + + + org.slf4j + slf4j-log4j12 + + + + + + com.google.code.gson + gson + + + + javax.servlet + javax.servlet-api + provided + + + + com.sun.jersey + jersey-server + + + + com.sun.jersey + jersey-client + + + + com.sun.jersey + jersey-servlet + ${jersey.version} + + + + com.thoughtworks.xstream + xstream + + + + org.apache.httpcomponents + httpclient + + + + org.restcomm + restcomm-connect.commons + ${project.version} + provided + + + + org.restcomm + restcomm-connect.dao + ${project.version} + provided + + + + diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AccountKey.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AccountKey.java new file mode 100644 index 0000000000..9d80b2c0fd --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AccountKey.java @@ -0,0 +1,49 @@ +package org.restcomm.connect.identity; + +import org.apache.commons.codec.digest.DigestUtils; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.entities.Account; + +/** + * Represents authorization information for an Account. When a request initially arrives carrying basic HTTP auth + * credentials an AccountKey is created. It carries the challenged credentials and the verification result. + * + * - use isVerified() to check the verification result. + * -use getAccount() to check if the account in the credentials actually exists (may not be verified) + * + * @author "Tsakiridis Orestis" + */ +public class AccountKey { + + private String challengedSid; + private String challengedKey; + private Account account; // Having this set does not mean it is verified. It just means that the (account) challengedSid exists. + private boolean verified = false; + + + public AccountKey(String sid, String key, AccountsDao dao) { + this.challengedSid = sid; // store there for future reference, maybe we need the raw data + this.challengedKey = key; + account = dao.getAccountToAuthenticate(sid); // We don't just retrieve an account, we're authenticating. Friendly names as authentnication tokens should be prevented + verify(dao); + } + + private void verify(AccountsDao dao) { + if ( account != null ) { + if ( challengedKey != null ) + // Compare both the plaintext version of the token and md5'ed version of it + if ( challengedKey.equals(account.getAuthToken()) || DigestUtils.md5Hex(challengedKey).equals(account.getAuthToken()) ) { + verified = true; + } + } + } + + public Account getAccount() { + return account; + } + + public boolean isVerified() { + return verified; + } + +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AuthOutcome.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AuthOutcome.java new file mode 100644 index 0000000000..efa1e48c5b --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/AuthOutcome.java @@ -0,0 +1,6 @@ +package org.restcomm.connect.identity; + +public enum AuthOutcome { + OK, + FAILED +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/EmailValidator.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/EmailValidator.java new file mode 100644 index 0000000000..08fc9185a1 --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/EmailValidator.java @@ -0,0 +1,52 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.identity; + +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; + +import org.apache.log4j.Logger; + +/** + * @author ddh.huy@gmail.com (Huy Dang) + */ +public class EmailValidator { + private static Logger logger = Logger.getLogger(EmailValidator.class); + + /** + * Verify an email address has valid format or not + * + * @param email: the email address need to be verified + * @return true if email format is valid, false if email format is invalid + */ + public static boolean isValidEmailFormat ( String email ) { + boolean isValid = false; + try { + InternetAddress emailAddress = new InternetAddress(email); + emailAddress.validate(); + isValid = true; + } catch (AddressException ex) { + isValid = false; + logger.warn("Email " + email + " is invalid"); + } + return isValid; + } +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/IdentityContext.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/IdentityContext.java new file mode 100644 index 0000000000..e984234ddd --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/IdentityContext.java @@ -0,0 +1,52 @@ +/* + * 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.identity; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.identity.shiro.RestcommRoles; + + +/** + * Identity Context holds all identity related entities whose lifecycle follows Restcomm lifecycle, such as + * keycloak deployment (to be added) and restcomm roles. + * + * In a typical use case you can access to the IdentityContext from the ServletContext. + * + * @author "Tsakiridis Orestis" + */ +public class IdentityContext { + RestcommRoles restcommRoles; + + /** + * @param restcommConfiguration An apache configuration object representing element of restcomm.xml + */ + public IdentityContext(Configuration restcommConfiguration) { + this.restcommRoles = new RestcommRoles(restcommConfiguration.subset("runtime-settings").subset("security-roles")); + } + + public IdentityContext(RestcommRoles restcommRoles) { + if (restcommRoles == null) + throw new IllegalArgumentException("Cannot create an IdentityContext object with null roles!"); + this.restcommRoles = restcommRoles; + } + + public RestcommRoles getRestcommRoles() { return restcommRoles; } + +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/UserIdentityContext.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/UserIdentityContext.java new file mode 100644 index 0000000000..f10d38803b --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/UserIdentityContext.java @@ -0,0 +1,135 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2016, 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.identity; + +import java.nio.charset.Charset; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.restcomm.connect.dao.exceptions.AccountHierarchyDepthCrossed; +import org.restcomm.connect.dao.AccountsDao; +import org.restcomm.connect.dao.entities.Account; + +/** + * A per-request security context providing access to Oauth tokens or Account API Keys. + * @author "Tsakiridis Orestis" + * + */ +public class UserIdentityContext { + + final AccountKey accountKey; + final Account effectiveAccount; // if oauthToken is set get the account that maps to it. Otherwise use account from accountKey + Set effectiveAccountRoles; + List accountLineage = null; // list of all parent account Sids up to the lop level account. It's initialized in a lazy way. + + AccountsDao accountsDao; + + /** + * After successfull creation of a UserIdentityContext object the following stands: + * - if an oauth token was present and verified *oauthToken* will contain it. Otherwise it will be null + * - TODO If a *linked* account exists for the oauth token username *effectiveAccount* will be set + * - if BASIC http credentials were present *accountKey* will contain them. Check accountKey.isVerified() + * - if BASIC http credentials were verified effective account will be set to this account. + * - if both oauthToken and accountKey are set and verified, effective account will be set to the account indicated by accountKey. + * @param request + * @param accountsDao + */ + public UserIdentityContext(HttpServletRequest request, AccountsDao accountsDao) { + this.accountsDao = accountsDao; + this.accountKey = extractAccountKey(request, accountsDao); + if (accountKey != null) { + if (accountKey.isVerified()) { + effectiveAccount = accountKey.getAccount(); + } else + effectiveAccount = null; + } else + effectiveAccount = null; + + if (effectiveAccount != null) + effectiveAccountRoles = extractAccountRoles(effectiveAccount); + } + + private Set extractAccountRoles(Account account) { + if (account == null) + return null; + Set roles = new HashSet(); + if (!StringUtils.isEmpty(account.getRole())) { + roles.add(account.getRole()); + } + return roles; + } + + private AccountKey extractAccountKey(HttpServletRequest request, AccountsDao dao) { + String authHeader = request.getHeader("Authorization"); + if (authHeader != null) { + String[] parts = authHeader.split(" "); + if (parts.length >= 2 && parts[0].equals("Basic")) { + String base64Credentials = parts[1].trim(); + String credentials = new String(Base64.decodeBase64(base64Credentials), Charset.forName("UTF-8")); + // credentials = username:password + final String[] values = credentials.split(":",2); + if (values.length >= 2) { + AccountKey accountKey = new AccountKey(values[0], values[1], dao); + return accountKey; + } + + } + } + return null; + } + + public AccountKey getAccountKey() { + return accountKey; + } + + public Account getEffectiveAccount() { + return effectiveAccount; + } + + public Set getEffectiveAccountRoles() { + return effectiveAccountRoles; + } + + /** + * Returns the list of ancestors for the effective (the one specified in the credentials) account + * in a lazy way. + * + * @return + */ + public List getEffectiveAccountLineage() { + if (accountLineage == null) { + if (effectiveAccount != null) { + try { + accountLineage = accountsDao.getAccountLineage(effectiveAccount); + } catch (AccountHierarchyDepthCrossed e) { + throw new RuntimeException("Logged account has a very big line of ancestors. Something seems wrong. Account sid: " + effectiveAccount.getSid().toString(), e); + } + } + } + return accountLineage; + } + +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidator.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidator.java new file mode 100644 index 0000000000..4236fdf985 --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidator.java @@ -0,0 +1,50 @@ +package org.restcomm.connect.identity.passwords; + +import org.apache.log4j.Logger; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class JavascriptPasswordValidator implements PasswordValidator { + + protected static Logger logger = Logger.getLogger(JavascriptPasswordValidator.class); + + @Override + public boolean isStrongEnough(String password) { + Integer result = getStrength(password); + if (result == null ||result < 50) + return false; + return true; + } + + /** + * Returns a number from 0-100 according to the strength of the password passed. + * In case of error it returns null. The actual implementation of the algorithm is implemented + * in Javascript hence the name of the class. + * + * @param password + * @return + */ + private Integer getStrength(String password) { + ScriptEngineManager factory = new ScriptEngineManager(); + ScriptEngine engine = factory.getEngineByName("JavaScript"); + + String js = "function getStrength(p) {var stringReverse = function(str) {for (var i = str.length - 1, out = ''; i >= 0; out += str[i--]) {}return out;},matches = {pos: {},neg: {}},counts = {pos: {},neg: {seqLetter: 0,seqNumber: 0,seqSymbol: 0}},tmp,strength = 0,letters = 'abcdefghijklmnopqrstuvwxyz',numbers = '01234567890',symbols = '\\\\!@#$%&/()=?¿',back,forth,i;if (p) {matches.pos.lower = p.match(/[a-z]/g);matches.pos.upper = p.match(/[A-Z]/g);matches.pos.numbers = p.match(/\\d/g);matches.pos.symbols = p.match(/[$-/:-?{-~!^_`\\[\\]]/g);matches.pos.middleNumber = p.slice(1, -1).match(/\\d/g);matches.pos.middleSymbol = p.slice(1, -1).match(/[$-/:-?{-~!^_`\\[\\]]/g);counts.pos.lower = matches.pos.lower ? matches.pos.lower.length : 0;counts.pos.upper = matches.pos.upper ? matches.pos.upper.length : 0;counts.pos.numbers = matches.pos.numbers ? matches.pos.numbers.length : 0;counts.pos.symbols = matches.pos.symbols ? matches.pos.symbols.length : 0;tmp = Object.keys(counts.pos).reduce(function(previous, key) {return previous + Math.min(1, counts.pos[key]);}, 0);counts.pos.numChars = p.length;tmp += (counts.pos.numChars >= 8) ? 1 : 0;counts.pos.requirements = (tmp >= 3) ? tmp : 0;counts.pos.middleNumber = matches.pos.middleNumber ? matches.pos.middleNumber.length : 0;counts.pos.middleSymbol = matches.pos.middleSymbol ? matches.pos.middleSymbol.length : 0;matches.neg.consecLower = p.match(/(?=([a-z]{2}))/g);matches.neg.consecUpper = p.match(/(?=([A-Z]{2}))/g);matches.neg.consecNumbers = p.match(/(?=(\\d{2}))/g);matches.neg.onlyNumbers = p.match(/^[0-9]*$/g);matches.neg.onlyLetters = p.match(/^([a-z]|[A-Z])*$/g);counts.neg.consecLower = matches.neg.consecLower ? matches.neg.consecLower.length : 0;counts.neg.consecUpper = matches.neg.consecUpper ? matches.neg.consecUpper.length : 0;counts.neg.consecNumbers = matches.neg.consecNumbers ? matches.neg.consecNumbers.length : 0;for (i = 0; i < letters.length - 2; i++) {var p2 = p.toLowerCase();forth = letters.substring(i, parseInt(i + 3));back = stringReverse(forth);if (p2.indexOf(forth) !== -1 || p2.indexOf(back) !== -1) {counts.neg.seqLetter++;}}for (i = 0; i < numbers.length - 2; i++) {forth = numbers.substring(i, parseInt(i + 3));back = stringReverse(forth);if (p.indexOf(forth) !== -1 || p.toLowerCase().indexOf(back) !== -1) {counts.neg.seqNumber++;}}for (i = 0; i < symbols.length - 2; i++) {forth = symbols.substring(i, parseInt(i + 3));back = stringReverse(forth);if (p.indexOf(forth) !== -1 || p.toLowerCase().indexOf(back) !== -1) {counts.neg.seqSymbol++;}}var repeats = {};var _p = p.toLowerCase();var arr = _p.split('');counts.neg.repeated = 0;for (i = 0; i < arr.length; i++) {var _reg = new RegExp(_p[i], 'g');var cnt = _p.match(_reg).length;if (cnt > 1 && !repeats[_p[i]]) {repeats[_p[i]] = cnt;counts.neg.repeated += cnt;}}strength += counts.pos.numChars * 4;if (counts.pos.upper) {strength += (counts.pos.numChars - counts.pos.upper) * 2;}if (counts.pos.lower) {strength += (counts.pos.numChars - counts.pos.lower) * 2;}if (counts.pos.upper || counts.pos.lower) {strength += counts.pos.numbers * 4;}strength += counts.pos.symbols * 6;strength += (counts.pos.middleSymbol + counts.pos.middleNumber) * 2;strength += counts.pos.requirements * 2;strength -= counts.neg.consecLower * 2;strength -= counts.neg.consecUpper * 2;strength -= counts.neg.consecNumbers * 2;strength -= counts.neg.seqNumber * 3;strength -= counts.neg.seqLetter * 3;strength -= counts.neg.seqSymbol * 3;if (matches.neg.onlyNumbers) {strength -= counts.pos.numChars;}if (matches.neg.onlyLetters) {strength -= counts.pos.numChars;}if (counts.neg.repeated) {strength -= (counts.neg.repeated / counts.pos.numChars) * 10;}}return Math.max(0, Math.min(100, Math.round(strength)));}"; + js += "var result = getStrength(password);"; + + try { + engine.put("password", password); + engine.eval(js); + Double result = (Double) engine.get("result"); + //throw new ScriptException("manally thrown"); + return result.intValue(); + } catch (ScriptException e) { + logger.error("Javascript-based password validation mechanism failed. Make sure a proper JAVA implementation is used.", e); + return null; + } + } +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidator.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidator.java new file mode 100644 index 0000000000..e21ec24a2d --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidator.java @@ -0,0 +1,10 @@ +package org.restcomm.connect.identity.passwords; + +/** + * Checks the strength of a password + * + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public interface PasswordValidator { + boolean isStrongEnough(String password); +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidatorFactory.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidatorFactory.java new file mode 100644 index 0000000000..0078b3f2b9 --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/passwords/PasswordValidatorFactory.java @@ -0,0 +1,10 @@ +package org.restcomm.connect.identity.passwords; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class PasswordValidatorFactory { + public static PasswordValidator createDefault() { + return new JavascriptPasswordValidator(); + } +} diff --git a/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/shiro/RestcommRoles.java b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/shiro/RestcommRoles.java new file mode 100644 index 0000000000..ff36d351e8 --- /dev/null +++ b/restcomm/restcomm.identity/src/main/java/org/restcomm/connect/identity/shiro/RestcommRoles.java @@ -0,0 +1,104 @@ +/* + * 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.identity.shiro; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.configuration.Configuration; +import org.apache.shiro.authz.Permission; +import org.apache.shiro.authz.SimpleRole; +import org.apache.shiro.authz.permission.WildcardPermission; + +/** + * @author orestis.tsakiridis@telestax.com (Orestis Tsakiridis) + */ +public class RestcommRoles { + private Map roles; + + /** + * Parses restcomm.xml configuration and builds a map out of roles from it. + * + * @param configuration - An apache configuration object based on the element + */ + public RestcommRoles(Configuration configuration) { + roles = new HashMap(); + loadSecurityRoles(configuration); + } + + public SimpleRole getRole(final String role) { + return roles.get(role); + } + + private void loadSecurityRoles(final Configuration configuration) { + @SuppressWarnings("unchecked") + final List roleNames = (List) configuration.getList("role[@name]"); + final int numberOfRoles = roleNames.size(); + if (numberOfRoles > 0) { + for (int roleIndex = 0; roleIndex < numberOfRoles; roleIndex++) { + StringBuilder buffer = new StringBuilder(); + buffer.append("role(").append(roleIndex).append(")").toString(); + final String prefix = buffer.toString(); + final String name = configuration.getString(prefix + "[@name]"); + @SuppressWarnings("unchecked") + final List permissions = configuration.getList(prefix + ".permission"); + + if (name != null) { + if (permissions.size() > 0 ) { + final SimpleRole role = new SimpleRole(name); + for (String permissionString: permissions) { + //logger.info("loading permission " + permissionString + " into " + name + " role"); + final Permission permission = new WildcardPermission(permissionString); + role.add(permission); + } + roles.put(name, role); + } + } + } + } + } + + @Override + public String toString() { + if ( roles == null || roles.size() == 0 ) + return "no roles defined"; + else { + StringBuffer buffer = new StringBuffer(); + for ( String role: roles.keySet() ) { + buffer.append(role); + SimpleRole simpleRole = roles.get(role); + Set permissions = simpleRole.getPermissions(); + buffer.append("["); + for (Permission permission: permissions) { + buffer.append(permission.toString()); + buffer.append(","); + } + buffer.append("]"); + } + return buffer.toString(); + } + } + +} + + + diff --git a/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/EmailValidatorTest.java b/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/EmailValidatorTest.java new file mode 100644 index 0000000000..d554aa2d20 --- /dev/null +++ b/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/EmailValidatorTest.java @@ -0,0 +1,51 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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.identity; + +import junit.framework.Assert; +import org.junit.Test; + +/** + * @author ddh.huy@gmail.com (Huy Dang) + */ +public class EmailValidatorTest { + @Test + public void emailValidationTest() { + Assert.assertFalse(EmailValidator.isValidEmailFormat("user")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user.email")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user@.email")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user@.email.com")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user@email.c")); + Assert.assertFalse(EmailValidator.isValidEmailFormat(".user@email.c")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user()@email.c")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user!!@email.c")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("test..user@email")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("test user@email.com")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user@email@test.com")); + Assert.assertFalse(EmailValidator.isValidEmailFormat("user@email.2j")); + + Assert.assertTrue(EmailValidator.isValidEmailFormat("test.email@email.test.com")); + Assert.assertTrue(EmailValidator.isValidEmailFormat("test-email@email-test.com")); + Assert.assertTrue(EmailValidator.isValidEmailFormat("testemail@email.com")); + Assert.assertTrue(EmailValidator.isValidEmailFormat("user+100@email.com")); + Assert.assertTrue(EmailValidator.isValidEmailFormat("user-100@email-test.com")); + } +} diff --git a/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidationTest.java b/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidationTest.java new file mode 100644 index 0000000000..bfc45a5774 --- /dev/null +++ b/restcomm/restcomm.identity/src/test/java/org/restcomm/connect/identity/passwords/JavascriptPasswordValidationTest.java @@ -0,0 +1,18 @@ +package org.restcomm.connect.identity.passwords; + +import junit.framework.Assert; +import org.junit.Test; + +/** + * @author otsakir@gmail.com - Orestis Tsakiridis + */ +public class JavascriptPasswordValidationTest { + @Test + public void passwordStrengthTest() { + PasswordValidator validator = PasswordValidatorFactory.createDefault(); + Assert.assertFalse(validator.isStrongEnough("1234")); + Assert.assertFalse(validator.isStrongEnough("asdf123")); + Assert.assertTrue(validator.isStrongEnough("asd123$#@")); + Assert.assertTrue(validator.isStrongEnough("γιωÏγος123#!@")); + } +} diff --git a/restcomm/restcomm.interpreter/pom.xml b/restcomm/restcomm.interpreter/pom.xml index ad96eb5bc1..181f97a1bf 100644 --- a/restcomm/restcomm.interpreter/pom.xml +++ b/restcomm/restcomm.interpreter/pom.xml @@ -2,13 +2,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.telestax.servlet - restcomm - 7.2.0-SNAPSHOT + org.restcomm + restcomm-connect + 8.3.0-SNAPSHOT - restcomm.interpreter - restcomm.interpreter + restcomm-connect.interpreter + restcomm-connect.interpreter @@ -53,64 +53,90 @@ - com.telestax.servlet - restcomm.commons + org.restcomm + restcomm-connect.commons ${project.version} provided - com.telestax.servlet - restcomm.dao + org.restcomm + restcomm-connect.dao ${project.version} provided - com.telestax.servlet - restcomm.asr + org.restcomm + restcomm-connect.email.api + ${project.version} + + + + org.restcomm + restcomm-connect.email + ${project.version} + + + + org.restcomm + restcomm-connect.asr + ${project.version} + provided + + + + org.restcomm + restcomm-connect.fax ${project.version} provided - com.telestax.servlet - restcomm.fax + org.restcomm + restcomm-connect.sms.api ${project.version} provided - com.telestax.servlet - restcomm.sms.api + org.restcomm + restcomm-connect.tts.api ${project.version} provided - com.telestax.servlet - restcomm.tts.api + org.restcomm + restcomm-connect.tts.acapela ${project.version} provided - com.telestax.servlet - restcomm.tts.voicerss + org.restcomm + restcomm-connect.tts.voicerss ${project.version} provided - com.telestax.servlet - restcomm.telephony.api + org.restcomm + restcomm-connect.telephony.api ${project.version} provided - com.telestax.servlet - restcomm.http + org.restcomm + restcomm-connect.mscontrol.api + ${project.version} + provided + + + + org.restcomm + restcomm-connect.http ${project.version} provided @@ -146,5 +172,11 @@ test + + org.mockito + mockito-core + test + + - + \ No newline at end of file diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/BaseVoiceInterpreter.java deleted file mode 100644 index acdf68c055..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/BaseVoiceInterpreter.java +++ /dev/null @@ -1,1884 +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.mobicents.servlet.restcomm.interpreter; - -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.pause; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.play; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.say; - -import java.io.File; -import java.io.IOException; -import java.math.BigDecimal; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; - -import org.apache.commons.configuration.Configuration; -import org.apache.http.NameValuePair; -import org.apache.http.message.BasicNameValuePair; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.asr.AsrInfo; -import org.mobicents.servlet.restcomm.asr.AsrRequest; -import org.mobicents.servlet.restcomm.asr.AsrResponse; -import org.mobicents.servlet.restcomm.asr.GetAsrInfo; -import org.mobicents.servlet.restcomm.asr.ISpeechAsr; -import org.mobicents.servlet.restcomm.cache.DiskCache; -import org.mobicents.servlet.restcomm.cache.DiskCacheRequest; -import org.mobicents.servlet.restcomm.cache.DiskCacheResponse; -import org.mobicents.servlet.restcomm.cache.HashGenerator; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.dao.RecordingsDao; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.dao.TranscriptionsDao; -import org.mobicents.servlet.restcomm.email.Mail; -import org.mobicents.servlet.restcomm.email.MailMan; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Recording; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; -import org.mobicents.servlet.restcomm.entities.SmsMessage.Direction; -import org.mobicents.servlet.restcomm.entities.SmsMessage.Status; -import org.mobicents.servlet.restcomm.entities.Transcription; -import org.mobicents.servlet.restcomm.fax.FaxRequest; -import org.mobicents.servlet.restcomm.fax.InterfaxService; -import org.mobicents.servlet.restcomm.fsm.Action; -import org.mobicents.servlet.restcomm.fsm.FiniteStateMachine; -import org.mobicents.servlet.restcomm.fsm.State; -import org.mobicents.servlet.restcomm.fsm.Transition; -import org.mobicents.servlet.restcomm.http.client.Downloader; -import org.mobicents.servlet.restcomm.http.client.DownloaderResponse; -import org.mobicents.servlet.restcomm.http.client.HttpRequestDescriptor; -import org.mobicents.servlet.restcomm.http.client.HttpResponseDescriptor; -import org.mobicents.servlet.restcomm.interpreter.rcml.Attribute; -import org.mobicents.servlet.restcomm.interpreter.rcml.GetNextVerb; -import org.mobicents.servlet.restcomm.interpreter.rcml.Parser; -import org.mobicents.servlet.restcomm.interpreter.rcml.Tag; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.sms.CreateSmsSession; -import org.mobicents.servlet.restcomm.sms.DestroySmsSession; -import org.mobicents.servlet.restcomm.sms.SmsServiceResponse; -import org.mobicents.servlet.restcomm.sms.SmsSessionAttribute; -import org.mobicents.servlet.restcomm.sms.SmsSessionInfo; -import org.mobicents.servlet.restcomm.sms.SmsSessionRequest; -import org.mobicents.servlet.restcomm.sms.SmsSessionResponse; -import org.mobicents.servlet.restcomm.telephony.Answer; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallStateChanged; -import org.mobicents.servlet.restcomm.telephony.Collect; -import org.mobicents.servlet.restcomm.telephony.GetCallInfo; -import org.mobicents.servlet.restcomm.telephony.Hangup; -import org.mobicents.servlet.restcomm.telephony.MediaGroupResponse; -import org.mobicents.servlet.restcomm.telephony.MediaGroupStateChanged; -import org.mobicents.servlet.restcomm.telephony.Play; -import org.mobicents.servlet.restcomm.telephony.Record; -import org.mobicents.servlet.restcomm.telephony.Reject; -import org.mobicents.servlet.restcomm.tts.api.GetSpeechSynthesizerInfo; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerInfo; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerRequest; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerResponse; -import org.mobicents.servlet.restcomm.util.UriUtils; -import org.mobicents.servlet.restcomm.util.WavUtils; - -import scala.concurrent.duration.Duration; -import akka.actor.Actor; -import akka.actor.ActorRef; -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.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; - -/** - * @author thomas.quintana@telestax.com (Thomas Quintana) - * @author jean.deruelle@telestax.com - * @author gvagenas@telestax.com - * @author pavel.slegr@telestax.com - */ -public abstract class BaseVoiceInterpreter extends UntypedActor { - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - - static final int ERROR_NOTIFICATION = 0; - static final int WARNING_NOTIFICATION = 1; - static final Pattern PATTERN = Pattern.compile("[\\*#0-9]{1,12}"); - static final String EMAIL_SENDER = "restcomm@restcomm.org"; - static final String EMAIL_SUBJECT = "RestComm Error Notification - Attention Required"; - - // States for the FSM. - // ========================== - final State uninitialized; - final State acquiringAsrInfo; - final State acquiringSynthesizerInfo; - final State acquiringCallInfo; - final State playingRejectionPrompt; - final State pausing; - final State caching; - final State checkingCache; - final State playing; - final State synthesizing; - final State redirecting; - final State faxing; - final State processingGatherChildren; - final State gathering; - final State finishGathering; - final State creatingRecording; - final State finishRecording; - final State creatingSmsSession; - final State sendingSms; - final State hangingUp; - // final State finished; - - // FSM. - FiniteStateMachine fsm = null; - // The user specific configuration. - Configuration configuration = null; - // The block storage cache. - ActorRef cache = null; - String cachePath = null; - // The downloader will fetch resources for us using HTTP. - ActorRef downloader = null; - // The mail man that will deliver e-mail. - ActorRef mailer = null; - // The call manager. - ActorRef callManager = null; - // The conference manager. - ActorRef conferenceManager = null; - // The automatic speech recognition service. - ActorRef asrService = null; - int outstandingAsrRequests; - // The fax service. - ActorRef faxService = null; - // The SMS service = null. - ActorRef smsService = null; - Map smsSessions = null; - // The storage engine. - DaoManager storage = null; - // The text to speech synthesizer service. - ActorRef synthesizer = null; - // The languages supported by the automatic speech recognition service. - AsrInfo asrInfo = null; - // The languages supported by the text to speech synthesizer service. - SpeechSynthesizerInfo synthesizerInfo = null; - // The call being handled by this interpreter. - ActorRef call = null; - ActorRef callMediaGroup = null; - // The information for this call. - CallInfo callInfo = null; - // The call state. - CallStateChanged.State callState = null; - // A call detail record. - CallDetailRecord callRecord = null; - - // State for outbound calls. - ActorRef outboundCall = null; - CallInfo outboundCallInfo = null; - - // State for the gather verb. - List gatherChildren = null; - List gatherPrompts = null; - // The call recording stuff. - Sid recordingSid = null; - URI recordingUri = null; - URI publicRecordingUri = null; - // Information to reach the application that will be executed - // by this interpreter. - Sid accountId; - Sid phoneId; - String version; - URI url; - String method; - URI fallbackUrl; - String fallbackMethod; - URI statusCallback; - String statusCallbackMethod; - String emailAddress; - // application data. - HttpRequestDescriptor request; - HttpResponseDescriptor response; - // The RCML parser. - ActorRef parser; - Tag verb; - - final Set transitions = new HashSet(); - - public BaseVoiceInterpreter() { - super(); - final ActorRef source = self(); - // 20 States in common - uninitialized = new State("uninitialized", null, null); - acquiringAsrInfo = new State("acquiring asr info", new AcquiringAsrInfo(source), null); - acquiringSynthesizerInfo = new State("acquiring tts info", new AcquiringSpeechSynthesizerInfo(source), null); - acquiringCallInfo = new State("acquiring call info", new AcquiringCallInfo(source), null); - playingRejectionPrompt = new State("playing rejection prompt", new PlayingRejectionPrompt(source), null); - pausing = new State("pausing", new Pausing(source), null); - caching = new State("caching", new Caching(source), null); - checkingCache = new State("checkingCache", new CheckCache(source), null); - playing = new State("playing", new Playing(source), null); - synthesizing = new State("synthesizing", new Synthesizing(source), null); - redirecting = new State("redirecting", new Redirecting(source), null); - faxing = new State("faxing", new Faxing(source), null); - gathering = new State("gathering", new Gathering(source), null); - processingGatherChildren = new State("processing gather children", new ProcessingGatherChildren(source), null); - finishGathering = new State("finish gathering", new FinishGathering(source), null); - creatingRecording = new State("creating recording", new CreatingRecording(source), null); - finishRecording = new State("finish recording", new FinishRecording(source), null); - creatingSmsSession = new State("creating sms session", new CreatingSmsSession(source), null); - sendingSms = new State("sending sms", new SendingSms(source), null); - hangingUp = new State("hanging up", new HangingUp(source), null); - - // Initialize the transitions for the FSM. - transitions.add(new Transition(uninitialized, acquiringAsrInfo)); - transitions.add(new Transition(acquiringAsrInfo, acquiringSynthesizerInfo)); - transitions.add(new Transition(acquiringSynthesizerInfo, acquiringCallInfo)); - transitions.add(new Transition(pausing, hangingUp)); - transitions.add(new Transition(playingRejectionPrompt, hangingUp)); - transitions.add(new Transition(faxing, faxing)); - transitions.add(new Transition(faxing, caching)); - transitions.add(new Transition(faxing, pausing)); - transitions.add(new Transition(faxing, redirecting)); - transitions.add(new Transition(faxing, synthesizing)); - transitions.add(new Transition(faxing, processingGatherChildren)); - transitions.add(new Transition(faxing, creatingRecording)); - transitions.add(new Transition(faxing, creatingSmsSession)); - transitions.add(new Transition(faxing, hangingUp)); - transitions.add(new Transition(caching, faxing)); - transitions.add(new Transition(caching, playing)); - transitions.add(new Transition(caching, caching)); - transitions.add(new Transition(caching, pausing)); - transitions.add(new Transition(caching, redirecting)); - transitions.add(new Transition(caching, synthesizing)); - transitions.add(new Transition(caching, processingGatherChildren)); - transitions.add(new Transition(caching, creatingRecording)); - transitions.add(new Transition(caching, creatingSmsSession)); - transitions.add(new Transition(caching, hangingUp)); - transitions.add(new Transition(checkingCache, synthesizing)); - transitions.add(new Transition(checkingCache, playing)); - transitions.add(new Transition(checkingCache, checkingCache)); - transitions.add(new Transition(playing, hangingUp)); - transitions.add(new Transition(synthesizing, faxing)); - transitions.add(new Transition(synthesizing, pausing)); - transitions.add(new Transition(synthesizing, checkingCache)); - transitions.add(new Transition(synthesizing, caching)); - transitions.add(new Transition(synthesizing, redirecting)); - transitions.add(new Transition(synthesizing, processingGatherChildren)); - transitions.add(new Transition(synthesizing, creatingRecording)); - transitions.add(new Transition(synthesizing, creatingSmsSession)); - transitions.add(new Transition(synthesizing, synthesizing)); - transitions.add(new Transition(synthesizing, hangingUp)); - transitions.add(new Transition(redirecting, faxing)); - transitions.add(new Transition(redirecting, pausing)); - transitions.add(new Transition(redirecting, checkingCache)); - transitions.add(new Transition(redirecting, caching)); - transitions.add(new Transition(redirecting, synthesizing)); - transitions.add(new Transition(redirecting, redirecting)); - transitions.add(new Transition(redirecting, processingGatherChildren)); - transitions.add(new Transition(redirecting, creatingRecording)); - transitions.add(new Transition(redirecting, creatingSmsSession)); - transitions.add(new Transition(redirecting, hangingUp)); - transitions.add(new Transition(creatingRecording, finishRecording)); - transitions.add(new Transition(creatingRecording, hangingUp)); - transitions.add(new Transition(finishRecording, faxing)); - transitions.add(new Transition(finishRecording, pausing)); - transitions.add(new Transition(finishRecording, checkingCache)); - transitions.add(new Transition(finishRecording, caching)); - transitions.add(new Transition(finishRecording, synthesizing)); - transitions.add(new Transition(finishRecording, redirecting)); - transitions.add(new Transition(finishRecording, processingGatherChildren)); - transitions.add(new Transition(finishRecording, creatingRecording)); - transitions.add(new Transition(finishRecording, creatingSmsSession)); - transitions.add(new Transition(finishRecording, hangingUp)); - transitions.add(new Transition(processingGatherChildren, processingGatherChildren)); - transitions.add(new Transition(processingGatherChildren, gathering)); - transitions.add(new Transition(processingGatherChildren, hangingUp)); - transitions.add(new Transition(gathering, finishGathering)); - transitions.add(new Transition(gathering, hangingUp)); - transitions.add(new Transition(finishGathering, faxing)); - transitions.add(new Transition(finishGathering, pausing)); - transitions.add(new Transition(finishGathering, checkingCache)); - transitions.add(new Transition(finishGathering, caching)); - transitions.add(new Transition(finishGathering, synthesizing)); - transitions.add(new Transition(finishGathering, redirecting)); - transitions.add(new Transition(finishGathering, processingGatherChildren)); - transitions.add(new Transition(finishGathering, creatingRecording)); - transitions.add(new Transition(finishGathering, creatingSmsSession)); - transitions.add(new Transition(finishGathering, hangingUp)); - transitions.add(new Transition(creatingSmsSession, sendingSms)); - transitions.add(new Transition(creatingSmsSession, hangingUp)); - transitions.add(new Transition(sendingSms, faxing)); - transitions.add(new Transition(sendingSms, pausing)); - transitions.add(new Transition(sendingSms, caching)); - transitions.add(new Transition(sendingSms, synthesizing)); - transitions.add(new Transition(sendingSms, redirecting)); - transitions.add(new Transition(sendingSms, processingGatherChildren)); - transitions.add(new Transition(sendingSms, creatingRecording)); - transitions.add(new Transition(sendingSms, creatingSmsSession)); - transitions.add(new Transition(sendingSms, hangingUp)); - } - - @Override - public abstract void onReceive(Object arg0) throws Exception; - - abstract List parameters(); - - ActorRef asr(final Configuration configuration) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public Actor create() throws Exception { - return new ISpeechAsr(configuration); - } - })); - } - - @SuppressWarnings("unchecked") - void asrResponse(final Object message) { - final Class klass = message.getClass(); - if (AsrResponse.class.equals(klass)) { - final AsrResponse response = (AsrResponse) message; - Transcription transcription = (Transcription) response.attributes().get("transcription"); - if (response.succeeded()) { - transcription = transcription.setStatus(Transcription.Status.COMPLETED); - transcription = transcription.setTranscriptionText(response.get()); - } else { - transcription = transcription.setStatus(Transcription.Status.FAILED); - } - final TranscriptionsDao transcriptions = storage.getTranscriptionsDao(); - transcriptions.updateTranscription(transcription); - // Notify the callback listener. - final Object attribute = response.attributes().get("callback"); - if (attribute != null) { - final URI callback = (URI) attribute; - final List parameters = parameters(); - request = new HttpRequestDescriptor(callback, "POST", parameters); - downloader.tell(request, null); - } - // Update pending asr responses. - outstandingAsrRequests--; - // Try to stop the interpreter. - postCleanup(); - } - } - - ActorRef fax(final Configuration configuration) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public Actor create() throws Exception { - return new InterfaxService(configuration); - } - })); - } - - void callback() { - if (statusCallback != null) { - if (statusCallbackMethod == null) { - statusCallbackMethod = "POST"; - } - final List parameters = parameters(); - request = new HttpRequestDescriptor(statusCallback, statusCallbackMethod, parameters); - downloader.tell(request, null); - } - } - - ActorRef cache(final String path, final String uri) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new DiskCache(path, uri, true); - } - })); - } - - ActorRef downloader() { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new Downloader(); - } - })); - } - - String e164(final String number) { - if (configuration.subset("runtime-settings").getBoolean("normalize-numbers-for-outbound-calls")) { - final PhoneNumberUtil numbersUtil = PhoneNumberUtil.getInstance(); - try { - final PhoneNumber result = numbersUtil.parse(number, "US"); - return numbersUtil.format(result, PhoneNumberFormat.E164); - } catch (final NumberParseException ignored) { - return number; - } - } else { - return number; - } - } - - void invalidVerb(final Tag verb) { - final ActorRef self = self(); - // Get the next verb. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, self); - } - - ActorRef mailer(final Configuration configuration) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new MailMan(configuration); - } - })); - } - - 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); - builder.setSid(sid); - builder.setAccountSid(accountId); - builder.setCallSid(callInfo.sid()); - builder.setApiVersion(version); - builder.setLog(log); - builder.setErrorCode(error); - final String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); - StringBuilder buffer = new StringBuilder(); - buffer.append(base); - if (!base.endsWith("/")) { - buffer.append("/"); - } - buffer.append(error).append(".html"); - final URI info = URI.create(buffer.toString()); - builder.setMoreInfo(info); - builder.setMessageText(message); - final DateTime now = DateTime.now(); - builder.setMessageDate(now); - if (request != null) { - builder.setRequestUrl(request.getUri()); - builder.setRequestMethod(request.getMethod()); - builder.setRequestVariables(request.getParametersAsString()); - } - if (response != null) { - builder.setResponseHeaders(response.getHeadersAsString()); - final String type = response.getContentType(); - if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - try { - builder.setResponseBody(response.getContentAsString()); - } catch (final IOException exception) { - logger.error( - "There was an error while reading the contents of the resource " + "located @ " + url.toString(), - exception); - } - } - } - buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/"); - buffer.append(accountId.toString()).append("/Notifications/"); - buffer.append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - return builder.build(); - } - - ActorRef parser(final String xml) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new Parser(xml); - } - })); - } - - void postCleanup() { - final ActorRef self = self(); - if (smsSessions.isEmpty() && outstandingAsrRequests == 0) { - final UntypedActorContext context = getContext(); - context.stop(self()); - } - } - - void sendMail(final Notification notification) { - if (emailAddress == null || emailAddress.isEmpty()) { - return; - } - final StringBuilder buffer = new StringBuilder(); - buffer.append("").append("Sid: ").append("
      "); - buffer.append(notification.getSid().toString()).append("
      "); - buffer.append("").append("Account Sid: ").append("
      "); - buffer.append(notification.getAccountSid().toString()).append("
      "); - buffer.append("").append("Call Sid: ").append("
      "); - buffer.append(notification.getCallSid().toString()).append("
      "); - buffer.append("").append("API Version: ").append("
      "); - buffer.append(notification.getApiVersion()).append("
      "); - buffer.append("").append("Log: ").append("
      "); - buffer.append(notification.getLog() == ERROR_NOTIFICATION ? "ERROR" : "WARNING").append("
      "); - buffer.append("").append("Error Code: ").append("
      "); - buffer.append(notification.getErrorCode()).append("
      "); - buffer.append("").append("More Information: ").append("
      "); - buffer.append(notification.getMoreInfo().toString()).append("
      "); - buffer.append("").append("Message Text: ").append("
      "); - buffer.append(notification.getMessageText()).append("
      "); - buffer.append("").append("Message Date: ").append("
      "); - buffer.append(notification.getMessageDate().toString()).append("
      "); - buffer.append("").append("Request URL: ").append("
      "); - buffer.append(notification.getRequestUrl().toString()).append("
      "); - buffer.append("").append("Request Method: ").append("
      "); - buffer.append(notification.getRequestMethod()).append("
      "); - buffer.append("").append("Request Variables: ").append("
      "); - buffer.append(notification.getRequestVariables()).append("
      "); - buffer.append("").append("Response Headers: ").append("
      "); - buffer.append(notification.getResponseHeaders()).append("
      "); - buffer.append("").append("Response Body: ").append("
      "); - buffer.append(notification.getResponseBody()).append("
      "); - final Mail email = new Mail(EMAIL_SENDER, emailAddress, EMAIL_SUBJECT, buffer.toString()); - mailer.tell(email, self()); - } - - void smsResponse(final Object message) { - final Class klass = message.getClass(); - final ActorRef self = self(); - if (SmsSessionResponse.class.equals(klass)) { - final SmsSessionResponse response = (SmsSessionResponse) message; - final SmsSessionInfo info = response.info(); - SmsMessage record = (SmsMessage) info.attributes().get("record"); - if (response.succeeded()) { - final DateTime now = DateTime.now(); - record = record.setDateSent(now); - record = record.setStatus(Status.SENT); - } else { - record = record.setStatus(Status.FAILED); - } - final SmsMessagesDao messages = storage.getSmsMessagesDao(); - messages.updateSmsMessage(record); - // Notify the callback listener. - final Object attribute = info.attributes().get("callback"); - if (attribute != null) { - final URI callback = (URI) attribute; - final List parameters = parameters(); - request = new HttpRequestDescriptor(callback, "POST", parameters); - downloader.tell(request, null); - } - // Destroy the sms session. - final ActorRef session = smsSessions.remove(record.getSid()); - final DestroySmsSession destroy = new DestroySmsSession(session); - smsService.tell(destroy, self); - // Try to stop the interpreter. - postCleanup(); - } - } - - ActorRef tts(final Configuration configuration) { - final String classpath = configuration.getString("[@class]"); - - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public Actor create() throws Exception { - return (UntypedActor) Class.forName(classpath).getConstructor(Configuration.class).newInstance(configuration); - } - })); - } - - abstract class AbstractAction implements Action { - protected final ActorRef source; - - public AbstractAction(final ActorRef source) { - super(); - this.source = source; - } - } - - final class AcquiringAsrInfo extends AbstractAction { - public AcquiringAsrInfo(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final StartInterpreter request = (StartInterpreter) message; - call = request.resource(); - asrService.tell(new GetAsrInfo(), source); - } - } - - final class AcquiringSpeechSynthesizerInfo extends AbstractAction { - public AcquiringSpeechSynthesizerInfo(final ActorRef source) { - super(source); - } - - @SuppressWarnings({ "unchecked" }) - @Override - public void execute(final Object message) throws Exception { - final AsrResponse response = (AsrResponse) message; - asrInfo = response.get(); - synthesizer.tell(new GetSpeechSynthesizerInfo(), source); - } - } - - final class AcquiringCallInfo extends AbstractAction { - public AcquiringCallInfo(final ActorRef source) { - super(source); - } - - @SuppressWarnings({ "unchecked" }) - @Override - public void execute(final Object message) throws Exception { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - synthesizerInfo = response.get(); - call.tell(new Observe(source), source); - call.tell(new GetCallInfo(), source); - } - } - - final class NotFound extends AbstractAction { - public NotFound(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - // final Class klass = message.getClass(); - final DownloaderResponse response = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { - logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); - } - final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " - + response.get().getURI()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - // Hang up the call. - call.tell(new org.mobicents.servlet.restcomm.telephony.NotFound(), source); - } - } - - final class Rejecting extends AbstractAction { - public Rejecting(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - String reason = "rejected"; - Attribute attribute = verb.attribute("reason"); - if (attribute != null) { - reason = attribute.value(); - if (reason != null && !reason.isEmpty()) { - if ("rejected".equalsIgnoreCase(reason)) { - reason = "rejected"; - } else if ("busy".equalsIgnoreCase(reason)) { - reason = "busy"; - } else { - reason = "rejected"; - } - } else { - reason = "rejected"; - } - } - // Reject the call. - if ("rejected".equals(reason)) { - call.tell(new Answer(), source); - } else { - call.tell(new Reject(), source); - } - } - } - - final class PlayingRejectionPrompt extends AbstractAction { - public PlayingRejectionPrompt(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - String path = configuration.subset("runtime-settings").getString("prompts-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - path += "reject.wav"; - URI uri = null; - try { - uri = URI.create(path); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final Play play = new Play(uri, 1); - callMediaGroup.tell(play, source); - } - } - - final class Faxing extends AbstractAction { - public Faxing(final ActorRef source) { - super(source); - } - - @Override - public void execute(Object message) throws Exception { - final DiskCacheResponse response = (DiskCacheResponse) message; - // Parse "from". - String from = callInfo.to(); - Attribute attribute = verb.attribute("from"); - if (attribute != null) { - from = attribute.value(); - if (from != null && from.isEmpty()) { - from = e164(from); - if (from == null) { - from = verb.attribute("from").value(); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - } - // Parse "to". - String to = callInfo.from(); - attribute = verb.attribute("to"); - if (attribute != null) { - to = attribute.value(); - if (to != null && !to.isEmpty()) { - to = e164(to); - if (to == null) { - to = verb.attribute("to").value(); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - } - // Send the fax. - final String uri = response.get().toString(); - final int offset = uri.lastIndexOf("/"); - final String path = cachePath + "/" + uri.substring(offset + 1, uri.length()); - final FaxRequest fax = new FaxRequest(to, new File(path)); - faxService.tell(fax, source); - } - } - - final class Pausing extends AbstractAction { - public Pausing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - int length = 1; - final Attribute attribute = verb.attribute("length"); - if (attribute != null) { - final String number = attribute.value(); - if (number != null && !number.isEmpty()) { - try { - length = Integer.parseInt(number); - } catch (final NumberFormatException exception) { - final Notification notification = notification(WARNING_NOTIFICATION, 13910, "Invalid length value."); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - } - } - } - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.create(length, TimeUnit.SECONDS)); - } - } - - final class CheckCache extends AbstractAction { - public CheckCache(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - // else { - // logger.info("Can't check cache, message not verb. Moving to the next verb"); - // // final GetNextVerb next = GetNextVerb.instance(); - // // parser.tell(next, source); - // return; - // } - String hash = hash(verb); - DiskCacheRequest request = new DiskCacheRequest(hash); - if (logger.isErrorEnabled()) { - logger.info("Checking cache for hash: " + hash); - } - cache.tell(request, source); - } - } - - final class Caching extends AbstractAction { - public Caching(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (SpeechSynthesizerResponse.class.equals(klass)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - final DiskCacheRequest request = new DiskCacheRequest(response.get()); - cache.tell(request, source); - } else if (Tag.class.equals(klass) || MediaGroupStateChanged.class.equals(klass)) { - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - // Parse the URL. - final String text = verb.text(); - if (text != null && !text.isEmpty()) { - // Try to cache the media. - URI target = null; - try { - target = URI.create(text); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - final DiskCacheRequest request = new DiskCacheRequest(uri); - cache.tell(request, source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - } - } - - final class Playing extends AbstractAction { - public Playing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (DiskCacheResponse.class.equals(klass)) { - // Parse the loop attribute. - int loop = 1; - final Attribute attribute = verb.attribute("loop"); - if (attribute != null) { - final String number = attribute.value(); - if (number != null && !number.isEmpty()) { - try { - loop = Integer.parseInt(number); - } catch (final NumberFormatException ignored) { - final NotificationsDao notifications = storage.getNotificationsDao(); - Notification notification = null; - if (say.equals(verb.name())) { - notification = notification(WARNING_NOTIFICATION, 13510, loop + " is an invalid loop value."); - notifications.addNotification(notification); - } else if (play.equals(verb.name())) { - notification = notification(WARNING_NOTIFICATION, 13410, loop + " is an invalid loop value."); - notifications.addNotification(notification); - } - } - } - } - final DiskCacheResponse response = (DiskCacheResponse) message; - final Play play = new Play(response.get(), loop); - callMediaGroup.tell(play, source); - } - } - } - - String hash(Object message) { - Map details = getSynthesizeDetails(message); - if (details == null) { - if (logger.isInfoEnabled()) { - logger.info("Cannot generate hash, details are null"); - } - return null; - } - String voice = details.get("voice"); - String language = details.get("language"); - String text = details.get("text"); - return HashGenerator.hashMessage(voice, language, text); - } - - Map getSynthesizeDetails(final Object message) { - final Class klass = message.getClass(); - - Map details = new HashMap(); - - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } else { - return null; - } - if (!say.equals(verb.name())) - return null; - - // Parse the voice attribute. - String voice = "man"; - Attribute attribute = verb.attribute("voice"); - if (attribute != null) { - voice = attribute.value(); - if (voice != null && !voice.isEmpty()) { - if (!"man".equals(voice) && !"woman".equals(voice)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13511, voice - + " is an invalid voice value."); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - voice = "man"; - } - } else { - voice = "man"; - } - } - // Parse the language attribute. - String language = "en"; - attribute = verb.attribute("language"); - if (attribute != null) { - language = attribute.value(); - if (language != null && !language.isEmpty()) { - if (!synthesizerInfo.languages().contains(language)) { - language = "en"; - } - } else { - language = "en"; - } - } - // Synthesize. - String text = verb.text(); - - details.put("voice", voice); - details.put("language", language); - details.put("text", text); - - return details; - - } - - final class Synthesizing extends AbstractAction { - public Synthesizing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - - final Class klass = message.getClass(); - - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - - Map details = getSynthesizeDetails(verb); - if (details != null && !details.isEmpty()) { - String voice = details.get("voice"); - String language = details.get("language"); - String text = details.get("text"); - final SpeechSynthesizerRequest synthesize = new SpeechSynthesizerRequest(voice, language, text); - synthesizer.tell(synthesize, source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - } - - final class HangingUp extends AbstractAction { - public HangingUp(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - // Hang up the call. - call.tell(new Hangup(), source); - } - } - - final class Redirecting extends AbstractAction { - public Redirecting(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - final NotificationsDao notifications = storage.getNotificationsDao(); - String method = "POST"; - Attribute attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13710, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - final String text = verb.text(); - if (text != null && !text.isEmpty()) { - // Try to redirect. - URI target = null; - try { - target = URI.create(text); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - final List parameters = parameters(); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - } - - abstract class AbstractGatherAction extends AbstractAction { - public AbstractGatherAction(final ActorRef source) { - super(source); - } - - protected String finishOnKey(final Tag container) { - String finishOnKey = "#"; - Attribute attribute = container.attribute("finishOnKey"); - if (attribute != null) { - finishOnKey = attribute.value(); - if (finishOnKey != null && !finishOnKey.isEmpty()) { - if (!PATTERN.matcher(finishOnKey).matches()) { - final NotificationsDao notifications = storage.getNotificationsDao(); - final Notification notification = notification(WARNING_NOTIFICATION, 13310, finishOnKey - + " is not a valid finishOnKey value"); - notifications.addNotification(notification); - finishOnKey = "#"; - } - } else { - finishOnKey = "#"; - } - } - return finishOnKey; - } - } - - final class ProcessingGatherChildren extends AbstractGatherAction { - public ProcessingGatherChildren(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - final NotificationsDao notifications = storage.getNotificationsDao(); - if (SpeechSynthesizerResponse.class.equals(klass)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - final DiskCacheRequest request = new DiskCacheRequest(response.get()); - cache.tell(request, source); - } else { - if (Tag.class.equals(klass)) { - verb = (Tag) message; - gatherPrompts = new ArrayList(); - gatherChildren = new ArrayList(verb.children()); - } else if (MediaGroupStateChanged.class.equals(klass)) { - gatherPrompts = new ArrayList(); - gatherChildren = new ArrayList(verb.children()); - } else if (DiskCacheResponse.class.equals(klass)) { - final DiskCacheResponse response = (DiskCacheResponse) message; - final URI uri = response.get(); - final Tag child = gatherChildren.remove(0); - // Parse the loop attribute. - int loop = 1; - final Attribute attribute = child.attribute("loop"); - if (attribute != null) { - final String number = attribute.value(); - if (number != null && !number.isEmpty()) { - try { - loop = Integer.parseInt(number); - } catch (final NumberFormatException ignored) { - Notification notification = null; - if (say.equals(child.name())) { - notification = notification(WARNING_NOTIFICATION, 13322, loop - + " is an invalid loop value."); - notifications.addNotification(notification); - } - } - } - } - for (int counter = 0; counter < loop; counter++) { - gatherPrompts.add(uri); - } - } - for (int index = 0; index < gatherChildren.size(); index++) { - final Tag child = gatherChildren.get(index); - if (play.equals(child.name())) { - final String text = child.text(); - if (text != null && !text.isEmpty()) { - URI target = null; - try { - target = URI.create(text); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 13325, text - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Cache the prompt. - final DiskCacheRequest request = new DiskCacheRequest(uri); - cache.tell(request, source); - break; - } - } else if (say.equals(child.name())) { - // Parse the voice attribute. - String voice = "man"; - Attribute attribute = child.attribute("voice"); - if (attribute != null) { - voice = attribute.value(); - if (voice != null && !voice.isEmpty()) { - if (!"man".equals(voice) && !"woman".equals(voice)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13321, voice - + " is an invalid voice value."); - notifications.addNotification(notification); - voice = "man"; - } - } else { - voice = "man"; - } - } - // Parse the language attribute. - String language = "en"; - attribute = child.attribute("language"); - if (attribute != null) { - language = attribute.value(); - if (language != null && !language.isEmpty()) { - if (!synthesizerInfo.languages().contains(language)) { - language = "en"; - } - } else { - language = "en"; - } - } - String text = child.text(); - if (text != null && !text.isEmpty()) { - final SpeechSynthesizerRequest synthesize = new SpeechSynthesizerRequest(voice, language, text); - synthesizer.tell(synthesize, source); - break; - } - } else if (pause.equals(child.name())) { - int length = 1; - final Attribute attribute = child.attribute("length"); - if (attribute != null) { - final String number = attribute.value(); - if (number != null && !number.isEmpty()) { - try { - length = Integer.parseInt(number); - } catch (final NumberFormatException ignored) { - } - } - } - String path = configuration.subset("runtime-settings").getString("prompts-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - path += "one-second-silence.wav"; - final URI uri = URI.create(path); - for (int counter = 0; counter < length; counter++) { - gatherPrompts.add(uri); - } - } - } - // Make sure we don't leave any pauses at the beginning - // since we can't concurrently modify the list. - if (!gatherChildren.isEmpty()) { - Tag child = null; - do { - child = gatherChildren.get(0); - if (child != null) { - if (pause.equals(child.name())) { - gatherChildren.remove(0); - } - } - } while (pause.equals(child.name())); - } - // Start gathering. - if (gatherChildren.isEmpty()) { - final StartGathering start = StartGathering.instance(); - source.tell(start, source); - } - } - } - } - - final class Gathering extends AbstractGatherAction { - public Gathering(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final NotificationsDao notifications = storage.getNotificationsDao(); - // Parse finish on key. - String finishOnKey = finishOnKey(verb); - // Parse the number of digits. - int numberOfDigits = Short.MAX_VALUE; - Attribute attribute = verb.attribute("numDigits"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - numberOfDigits = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final Notification notification = notification(WARNING_NOTIFICATION, 13314, numberOfDigits - + " is not a valid numDigits value"); - notifications.addNotification(notification); - } - } - } - // Parse timeout. - int timeout = 5; - attribute = verb.attribute("timeout"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - timeout = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final Notification notification = notification(WARNING_NOTIFICATION, 13313, timeout - + " is not a valid timeout value"); - notifications.addNotification(notification); - } - } - } - // Start gathering. - final Collect collect = new Collect(gatherPrompts, null, timeout, finishOnKey, numberOfDigits); - callMediaGroup.tell(collect, source); - // Some clean up. - gatherChildren = null; - gatherPrompts = null; - } - } - - final class FinishGathering extends AbstractGatherAction { - public FinishGathering(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final NotificationsDao notifications = storage.getNotificationsDao(); - final MediaGroupResponse response = (MediaGroupResponse) message; - // Parses "action". - Attribute attribute = verb.attribute("action"); - String digits = response.get(); - final String finishOnKey = finishOnKey(verb); - if (digits.equals(finishOnKey)) { - digits = ""; - } - if (logger.isDebugEnabled()) { - logger.debug("Digits collected : " + digits); - } - // https://bitbucket.org/telestax/telscale-restcomm/issue/150/verb-is-looping-by-default-and-never - // If the 'timeout' is reached before the caller enters any digits, or if the caller enters the 'finishOnKey' value - // before entering any other digits, Twilio will not make a request to the 'action' URL but instead continue - // processing - // the current TwiML document with the verb immediately following the - if (attribute != null && (digits != null && !digits.trim().isEmpty())) { - String action = attribute.value(); - if (action != null && !action.isEmpty()) { - URI target = null; - try { - target = URI.create(action); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, action - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Parse "method". - String method = "POST"; - attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 14104, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - // Redirect to the action url. - if (digits.endsWith(finishOnKey)) { - final int finishOnKeyIndex = digits.lastIndexOf(finishOnKey); - digits = digits.substring(0, finishOnKeyIndex); - } - final List parameters = parameters(); - parameters.add(new BasicNameValuePair("Digits", digits)); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, source); - return; - } - } - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - - final class CreatingRecording extends AbstractAction { - public CreatingRecording(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - final NotificationsDao notifications = storage.getNotificationsDao(); - String finishOnKey = "1234567890*#"; - Attribute attribute = verb.attribute("finishOnKey"); - if (attribute != null) { - finishOnKey = attribute.value(); - if (finishOnKey != null && !finishOnKey.isEmpty()) { - if (!PATTERN.matcher(finishOnKey).matches()) { - final Notification notification = notification(WARNING_NOTIFICATION, 13613, finishOnKey - + " is not a valid finishOnKey value"); - notifications.addNotification(notification); - finishOnKey = "1234567890*#"; - } - } else { - finishOnKey = "1234567890*#"; - } - } - boolean playBeep = true; - attribute = verb.attribute("playBeep"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - playBeep = Boolean.parseBoolean(value); - } - } - int maxLength = 3600; - attribute = verb.attribute("maxLength"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - maxLength = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final Notification notification = notification(WARNING_NOTIFICATION, 13612, maxLength - + " is not a valid maxLength value"); - notifications.addNotification(notification); - } - } - } - int timeout = 5; - attribute = verb.attribute("timeout"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - timeout = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final Notification notification = notification(WARNING_NOTIFICATION, 13612, timeout - + " is not a valid timeout value"); - notifications.addNotification(notification); - } - } - } - // Start recording. - recordingSid = Sid.generate(Sid.Type.RECORDING); - String path = configuration.subset("runtime-settings").getString("recordings-path"); - String httpRecordingUri = configuration.subset("runtime-settings").getString("recordings-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - if (!httpRecordingUri.endsWith("/")) { - httpRecordingUri += "/"; - } - path += recordingSid.toString() + ".wav"; - httpRecordingUri += recordingSid.toString() + ".wav"; - recordingUri = URI.create(path); - publicRecordingUri = URI.create(httpRecordingUri); - Record record = null; - if (playBeep) { - final List prompts = new ArrayList(1); - path = configuration.subset("runtime-settings").getString("prompts-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - path += "beep.wav"; - try { - prompts.add(URI.create(path)); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - record = new Record(recordingUri, prompts, timeout, maxLength, finishOnKey); - } else { - record = new Record(recordingUri, timeout, maxLength, finishOnKey); - } - callMediaGroup.tell(record, source); - } - } - - final class FinishRecording extends AbstractAction { - public FinishRecording(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallStateChanged.class.equals(klass)) { - final CallStateChanged event = (CallStateChanged) message; - // Update the interpreter state. - callState = event.state(); - // Update the storage. - callRecord = callRecord.setStatus(callState.toString()); - final DateTime end = DateTime.now(); - callRecord = callRecord.setEndTime(end); - final int seconds = (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000; - callRecord = callRecord.setDuration(seconds); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - records.updateCallDetailRecord(callRecord); - // Update the application. - callback(); - } - final NotificationsDao notifications = storage.getNotificationsDao(); - // Create a record of the recording. - Double duration = WavUtils.getAudioDuration(recordingUri); - if(duration.equals(0.0)) { - final DateTime end = DateTime.now(); - duration = new Double((end.getMillis() - callRecord.getStartTime().getMillis()) / 1000); - } - final Recording.Builder builder = Recording.builder(); - builder.setSid(recordingSid); - builder.setAccountSid(accountId); - builder.setCallSid(callInfo.sid()); - builder.setDuration(duration); - builder.setApiVersion(version); - StringBuilder buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/").append(accountId.toString()); - buffer.append("/Recordings/").append(recordingSid.toString()); - builder.setUri(URI.create(buffer.toString())); - final Recording recording = builder.build(); - final RecordingsDao recordings = storage.getRecordingsDao(); - recordings.addRecording(recording); - // Start transcription. - URI transcribeCallback = null; - Attribute attribute = verb.attribute("transcribeCallback"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - transcribeCallback = URI.create(value); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, transcribeCallback - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - } - boolean transcribe = false; - if (transcribeCallback != null) { - transcribe = true; - } else { - attribute = verb.attribute("transcribe"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - transcribe = Boolean.parseBoolean(value); - } - } - } - if (transcribe) { - final Sid sid = Sid.generate(Sid.Type.TRANSCRIPTION); - final Transcription.Builder otherBuilder = Transcription.builder(); - otherBuilder.setSid(sid); - otherBuilder.setAccountSid(accountId); - otherBuilder.setStatus(Transcription.Status.IN_PROGRESS); - otherBuilder.setRecordingSid(recordingSid); - otherBuilder.setDuration(duration); - otherBuilder.setPrice(new BigDecimal("0.00")); - buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/").append(accountId.toString()); - buffer.append("/Transcriptions/").append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - otherBuilder.setUri(uri); - final Transcription transcription = otherBuilder.build(); - final TranscriptionsDao transcriptions = storage.getTranscriptionsDao(); - transcriptions.addTranscription(transcription); - try { - final Map attributes = new HashMap(); - attributes.put("callback", transcribeCallback); - attributes.put("transcription", transcription); - asrService.tell(new AsrRequest(new File(recordingUri), "en", attributes), source); - outstandingAsrRequests++; - } catch (final Exception exception) { - logger.error(exception.getMessage(), exception); - } - } - // If action is present redirect to the action URI. - attribute = verb.attribute("action"); - if (attribute != null) { - String action = attribute.value(); - if (action != null && !action.isEmpty()) { - URI target = null; - try { - target = URI.create(action); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, action - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Parse "method". - String method = "POST"; - attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13610, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - // Redirect to the action url. - String httpRecordingUri = configuration.subset("runtime-settings").getString("recordings-uri"); - if (!httpRecordingUri.endsWith("/")) { - httpRecordingUri += "/"; - } - httpRecordingUri += recordingSid.toString() + ".wav"; - URI publicRecordingUri = URI.create(httpRecordingUri); - final List parameters = parameters(); - parameters.add(new BasicNameValuePair("RecordingUrl", recordingUri.toString())); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", publicRecordingUri.toString())); - parameters.add(new BasicNameValuePair("RecordingDuration", Double.toString(duration))); - if (MediaGroupResponse.class.equals(klass)) { - final MediaGroupResponse response = (MediaGroupResponse) message; - parameters.add(new BasicNameValuePair("Digits", response.get())); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, source); - } else if (CallStateChanged.class.equals(klass)) { - parameters.add(new BasicNameValuePair("Digits", "hangup")); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, null); - source.tell(StopInterpreter.instance(), source); - } - // A little clean up. - recordingSid = null; - recordingUri = null; - return; - } - } - if (CallStateChanged.class.equals(klass)) { - source.tell(StopInterpreter.instance(), source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - // A little clean up. - recordingSid = null; - recordingUri = null; - } - } - - final class CreatingSmsSession extends AbstractAction { - public CreatingSmsSession(final ActorRef source) { - super(source); - } - - @Override - public void execute(Object message) throws Exception { - // Save verb. - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - // Create a new sms session to handle the verb. - smsService.tell(new CreateSmsSession(), source); - } - } - - final class SendingSms extends AbstractAction { - public SendingSms(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final SmsServiceResponse response = (SmsServiceResponse) message; - final ActorRef session = response.get(); - final NotificationsDao notifications = storage.getNotificationsDao(); - // Parse "from". - String from = callInfo.to(); - Attribute attribute = verb.attribute("from"); - if (attribute != null) { - from = attribute.value(); - if (from != null && !from.isEmpty()) { - from = e164(from); - if (from == null) { - from = verb.attribute("from").value(); - final Notification notification = notification(ERROR_NOTIFICATION, 14102, from - + " is an invalid 'from' phone number."); - notifications.addNotification(notification); - sendMail(notification); - smsService.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - } - // Parse "to". - String to = callInfo.from(); - attribute = verb.attribute("to"); - if (attribute != null) { - to = attribute.value(); - if (to != null && !to.isEmpty()) { - to = e164(to); - if (to == null) { - to = verb.attribute("to").value(); - final Notification notification = notification(ERROR_NOTIFICATION, 14101, to - + " is an invalid 'to' phone number."); - notifications.addNotification(notification); - sendMail(notification); - smsService.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - } - // Parse text. - String body = verb.text(); - if (body == null || body.isEmpty()) { - final Notification notification = notification(ERROR_NOTIFICATION, 14103, body + " is an invalid SMS body."); - notifications.addNotification(notification); - sendMail(notification); - smsService.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } else { - // Start observing events from the sms session. - session.tell(new Observe(source), source); - // Store the status callback in the sms session. - attribute = verb.attribute("statusCallback"); - if (attribute != null) { - String callback = attribute.value(); - if (callback != null && !callback.isEmpty()) { - URI target = null; - try { - target = URI.create(callback); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 14105, callback - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - smsService.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - session.tell(new SmsSessionAttribute("callback", uri), source); - } - } - // Create an SMS detail record. - final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); - final SmsMessage.Builder builder = SmsMessage.builder(); - builder.setSid(sid); - builder.setAccountSid(accountId); - builder.setApiVersion(version); - builder.setRecipient(to); - builder.setSender(from); - builder.setBody(body); - builder.setDirection(Direction.OUTBOUND_REPLY); - builder.setStatus(Status.SENDING); - builder.setPrice(new BigDecimal("0.00")); - final StringBuilder buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/"); - buffer.append(accountId.toString()).append("/SMS/Messages/"); - buffer.append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - final SmsMessage record = builder.build(); - final SmsMessagesDao messages = storage.getSmsMessagesDao(); - messages.addSmsMessage(record); - // Store the sms record in the sms session. - session.tell(new SmsSessionAttribute("record", record), source); - // Send the SMS. - final SmsSessionRequest sms = new SmsSessionRequest(from, to, body, null); - session.tell(sms, source); - smsSessions.put(sid, session); - } - // Parses "action". - attribute = verb.attribute("action"); - if (attribute != null) { - String action = attribute.value(); - if (action != null && !action.isEmpty()) { - URI target = null; - try { - target = URI.create(action); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, action - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Parse "method". - String method = "POST"; - attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 14104, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - // Redirect to the action url. - final List parameters = parameters(); - final String status = Status.SENDING.toString(); - parameters.add(new BasicNameValuePair("SmsStatus", status)); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, source); - return; - } - } - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreterBuilder.java deleted file mode 100644 index a4b90818b9..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreterBuilder.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.mobicents.servlet.restcomm.interpreter; - -import java.net.URI; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.telephony.CallInfo; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; - -public class ConfVoiceInterpreterBuilder { - - 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() { - return system.actorOf(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); - } - })); - } - - 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/mobicents/servlet/restcomm/interpreter/Fork.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/Fork.java deleted file mode 100644 index 095d8d1c7c..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/Fork.java +++ /dev/null @@ -1,40 +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.mobicents.servlet.restcomm.interpreter; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class Fork { - private static final class Singleton { - private static final Fork instance = new Fork(); - } - - private Fork() { - super(); - } - - public static Fork instance() { - return Singleton.instance; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreterBuilder.java deleted file mode 100644 index e5ad023669..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreterBuilder.java +++ /dev/null @@ -1,101 +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.mobicents.servlet.restcomm.interpreter; - -import java.net.URI; - -import org.apache.commons.configuration.Configuration; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Sid; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class SmsInterpreterBuilder { - 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() { - return system.actorOf(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); - } - })); - } - - 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/mobicents/servlet/restcomm/interpreter/StartForking.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartForking.java deleted file mode 100644 index b95b0ab9e6..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartForking.java +++ /dev/null @@ -1,40 +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.mobicents.servlet.restcomm.interpreter; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class StartForking { - private static final class Singleton { - private static final StartForking instance = new StartForking(); - } - - private StartForking() { - super(); - } - - public static StartForking instance() { - return Singleton.instance; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StopInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StopInterpreter.java deleted file mode 100644 index 083dfc6dfe..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StopInterpreter.java +++ /dev/null @@ -1,40 +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.mobicents.servlet.restcomm.interpreter; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class StopInterpreter { - private static final class Singleton { - private static final StopInterpreter instance = new StopInterpreter(); - } - - private StopInterpreter() { - super(); - } - - public static StopInterpreter instance() { - return Singleton.instance; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreter.java deleted file mode 100644 index 8aec86af17..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreter.java +++ /dev/null @@ -1,784 +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.mobicents.servlet.restcomm.interpreter; - -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.fax; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.gather; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.hangup; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.pause; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.play; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.record; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.redirect; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.reject; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.say; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.sms; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.sip.SipServletResponse; - -import org.apache.commons.configuration.Configuration; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.message.BasicNameValuePair; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.asr.AsrResponse; -import org.mobicents.servlet.restcomm.cache.DiskCacheResponse; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.fax.FaxResponse; -import org.mobicents.servlet.restcomm.fsm.Action; -import org.mobicents.servlet.restcomm.fsm.FiniteStateMachine; -import org.mobicents.servlet.restcomm.fsm.State; -import org.mobicents.servlet.restcomm.fsm.Transition; -import org.mobicents.servlet.restcomm.http.client.DownloaderResponse; -import org.mobicents.servlet.restcomm.http.client.HttpRequestDescriptor; -import org.mobicents.servlet.restcomm.interpreter.rcml.Attribute; -import org.mobicents.servlet.restcomm.interpreter.rcml.End; -import org.mobicents.servlet.restcomm.interpreter.rcml.GetNextVerb; -import org.mobicents.servlet.restcomm.interpreter.rcml.Tag; -import org.mobicents.servlet.restcomm.interpreter.rcml.Verbs; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.sms.SmsServiceResponse; -import org.mobicents.servlet.restcomm.sms.SmsSessionResponse; -import org.mobicents.servlet.restcomm.telephony.Answer; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallResponse; -import org.mobicents.servlet.restcomm.telephony.CallStateChanged; -import org.mobicents.servlet.restcomm.telephony.Cancel; -import org.mobicents.servlet.restcomm.telephony.CreateCall; -import org.mobicents.servlet.restcomm.telephony.CreateMediaGroup; -import org.mobicents.servlet.restcomm.telephony.DestroyCall; -import org.mobicents.servlet.restcomm.telephony.DestroyMediaGroup; -import org.mobicents.servlet.restcomm.telephony.MediaGroupResponse; -import org.mobicents.servlet.restcomm.telephony.MediaGroupStateChanged; -import org.mobicents.servlet.restcomm.telephony.MediaGroupStatus; -import org.mobicents.servlet.restcomm.telephony.Reject; -import org.mobicents.servlet.restcomm.telephony.StartMediaGroup; -import org.mobicents.servlet.restcomm.telephony.StopMediaGroup; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerResponse; - -import akka.actor.ActorRef; -import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActorContext; -import akka.event.Logging; -import akka.event.LoggingAdapter; - -/** - * @author gvagenas@telestax.com - * @author jean.deruelle@telestax.com - * @author pavel.slegr@telestax.com - */ -public final class SubVoiceInterpreter extends BaseVoiceInterpreter { - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - // States for the FSM. - private final State downloadingRcml; - private final State initializingCallMediaGroup; - private final State acquiringCallMediaGroup; - private final State ready; - private final State notFound; - private final State rejecting; - private final State finished; - private final State checkingMediaGroupState; - - // application data. - private DownloaderResponse downloaderResponse; - private ActorRef source; - private Boolean hangupOnEnd; - private ActorRef originalInterpreter; - - 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) { - - 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) { - super(); - source = self(); - acquiringCallMediaGroup = new State("acquiring call media group", new AcquiringCallMediaGroup(source), null); - downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); - initializingCallMediaGroup = new State("initializing call media group", new InitializingCallMediaGroup(source), null); - ready = new State("ready", new Ready(source), null); - notFound = new State("notFound", new NotFound(source), null); - rejecting = new State("rejecting", new Rejecting(source), null); - finished = new State("finished", new Finished(source), null); - checkingMediaGroupState = new State("checkingMediaGroupState", new CheckMediaGroupState(source), null); - - transitions.add(new Transition(acquiringAsrInfo, finished)); - transitions.add(new Transition(acquiringSynthesizerInfo, finished)); - transitions.add(new Transition(acquiringCallInfo, downloadingRcml)); - transitions.add(new Transition(acquiringCallInfo, finished)); - - transitions.add(new Transition(acquiringCallMediaGroup, checkingMediaGroupState)); - transitions.add(new Transition(acquiringCallMediaGroup, initializingCallMediaGroup)); - transitions.add(new Transition(acquiringCallMediaGroup, hangingUp)); - transitions.add(new Transition(acquiringCallMediaGroup, finished)); - - transitions.add(new Transition(checkingMediaGroupState, initializingCallMediaGroup)); - transitions.add(new Transition(checkingMediaGroupState, faxing)); - transitions.add(new Transition(checkingMediaGroupState, downloadingRcml)); - transitions.add(new Transition(checkingMediaGroupState, playingRejectionPrompt)); - transitions.add(new Transition(checkingMediaGroupState, pausing)); - transitions.add(new Transition(checkingMediaGroupState, checkingCache)); - transitions.add(new Transition(checkingMediaGroupState, caching)); - transitions.add(new Transition(checkingMediaGroupState, synthesizing)); - transitions.add(new Transition(checkingMediaGroupState, redirecting)); - transitions.add(new Transition(checkingMediaGroupState, processingGatherChildren)); - transitions.add(new Transition(checkingMediaGroupState, creatingRecording)); - transitions.add(new Transition(checkingMediaGroupState, creatingSmsSession)); - transitions.add(new Transition(checkingMediaGroupState, hangingUp)); - transitions.add(new Transition(checkingMediaGroupState, finished)); - transitions.add(new Transition(checkingMediaGroupState, ready)); - - transitions.add(new Transition(initializingCallMediaGroup, faxing)); - transitions.add(new Transition(initializingCallMediaGroup, downloadingRcml)); - transitions.add(new Transition(initializingCallMediaGroup, playingRejectionPrompt)); - transitions.add(new Transition(initializingCallMediaGroup, pausing)); - transitions.add(new Transition(initializingCallMediaGroup, checkingCache)); - transitions.add(new Transition(initializingCallMediaGroup, caching)); - transitions.add(new Transition(initializingCallMediaGroup, synthesizing)); - transitions.add(new Transition(initializingCallMediaGroup, redirecting)); - transitions.add(new Transition(initializingCallMediaGroup, processingGatherChildren)); - transitions.add(new Transition(initializingCallMediaGroup, creatingRecording)); - transitions.add(new Transition(initializingCallMediaGroup, creatingSmsSession)); - transitions.add(new Transition(initializingCallMediaGroup, hangingUp)); - transitions.add(new Transition(initializingCallMediaGroup, finished)); - transitions.add(new Transition(initializingCallMediaGroup, ready)); - transitions.add(new Transition(downloadingRcml, ready)); - transitions.add(new Transition(downloadingRcml, notFound)); - transitions.add(new Transition(downloadingRcml, hangingUp)); - transitions.add(new Transition(downloadingRcml, finished)); - transitions.add(new Transition(downloadingRcml, acquiringCallMediaGroup)); - transitions.add(new Transition(ready, faxing)); - transitions.add(new Transition(ready, pausing)); - transitions.add(new Transition(ready, checkingCache)); - transitions.add(new Transition(ready, caching)); - transitions.add(new Transition(ready, synthesizing)); - transitions.add(new Transition(ready, rejecting)); - transitions.add(new Transition(ready, redirecting)); - transitions.add(new Transition(ready, processingGatherChildren)); - transitions.add(new Transition(ready, creatingRecording)); - transitions.add(new Transition(ready, creatingSmsSession)); - transitions.add(new Transition(ready, hangingUp)); - transitions.add(new Transition(ready, finished)); - transitions.add(new Transition(pausing, ready)); - transitions.add(new Transition(pausing, finished)); - transitions.add(new Transition(rejecting, acquiringCallMediaGroup)); - transitions.add(new Transition(rejecting, finished)); - transitions.add(new Transition(faxing, ready)); - transitions.add(new Transition(faxing, finished)); - transitions.add(new Transition(caching, finished)); - transitions.add(new Transition(playing, ready)); - transitions.add(new Transition(playing, finished)); - transitions.add(new Transition(synthesizing, finished)); - transitions.add(new Transition(redirecting, ready)); - transitions.add(new Transition(redirecting, finished)); - transitions.add(new Transition(creatingRecording, finished)); - transitions.add(new Transition(finishRecording, ready)); - transitions.add(new Transition(finishRecording, finished)); - transitions.add(new Transition(processingGatherChildren, finished)); - transitions.add(new Transition(gathering, finished)); - transitions.add(new Transition(finishGathering, finished)); - transitions.add(new Transition(creatingSmsSession, finished)); - transitions.add(new Transition(sendingSms, ready)); - transitions.add(new Transition(sendingSms, finished)); - transitions.add(new Transition(hangingUp, finished)); - - // 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.callManager = callManager; - this.asrService = asr(configuration.subset("speech-recognizer")); - this.faxService = fax(configuration.subset("fax-service")); - this.smsService = sms; - this.smsSessions = new HashMap(); - this.storage = storage; - this.synthesizer = tts(configuration.subset("speech-synthesizer")); - this.mailer = mailer(configuration.subset("smtp")); - final Configuration runtime = configuration.subset("runtime-settings"); - String path = runtime.getString("cache-path"); - if (!path.endsWith("/")) { - path = path + "/"; - } - path = path + accountId.toString(); - cachePath = path; - String uri = runtime.getString("cache-uri"); - if (!uri.endsWith("/")) { - uri = uri + "/"; - } - uri = uri + accountId.toString(); - this.cache = cache(path, uri); - this.downloader = downloader(); - this.hangupOnEnd = hangupOnEnd; - } - - 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); - builder.setSid(sid); - builder.setAccountSid(accountId); - builder.setCallSid(callInfo.sid()); - builder.setApiVersion(version); - builder.setLog(log); - builder.setErrorCode(error); - final String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); - StringBuilder buffer = new StringBuilder(); - buffer.append(base); - if (!base.endsWith("/")) { - buffer.append("/"); - } - buffer.append(error).append(".html"); - final URI info = URI.create(buffer.toString()); - builder.setMoreInfo(info); - builder.setMessageText(message); - final DateTime now = DateTime.now(); - builder.setMessageDate(now); - if (request != null) { - builder.setRequestUrl(request.getUri()); - builder.setRequestMethod(request.getMethod()); - builder.setRequestVariables(request.getParametersAsString()); - } - if (response != null) { - builder.setResponseHeaders(response.getHeadersAsString()); - final String type = response.getContentType(); - if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - try { - builder.setResponseBody(response.getContentAsString()); - } catch (final IOException exception) { - logger.error( - "There was an error while reading the contents of the resource " + "located @ " + url.toString(), - exception); - } - } - } - buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/"); - buffer.append(accountId.toString()).append("/Notifications/"); - buffer.append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - return builder.build(); - } - - @SuppressWarnings("unchecked") - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - final State state = fsm.state(); - final ActorRef sender = sender(); - - if (logger.isInfoEnabled()) { - logger.info(" ********** SubVoiceInterpreter's Current State: " + state.toString()); - logger.info(" ********** SubVoiceInterpreter's Processing Message: " + klass.getName()); - } - - if (StartInterpreter.class.equals(klass)) { - originalInterpreter = sender; - fsm.transition(message, acquiringAsrInfo); - } else if (AsrResponse.class.equals(klass)) { - if (outstandingAsrRequests > 0) { - asrResponse(message); - } else { - fsm.transition(message, acquiringSynthesizerInfo); - } - } else if (SpeechSynthesizerResponse.class.equals(klass)) { - if (acquiringSynthesizerInfo.equals(state)) { - fsm.transition(message, acquiringCallInfo); - } else if (synthesizing.equals(state)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - if (response.succeeded()) { - fsm.transition(message, caching); - } else { - fsm.transition(message, hangingUp); - } - } else if (processingGatherChildren.equals(state)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - if (response.succeeded()) { - fsm.transition(message, processingGatherChildren); - } else { - fsm.transition(message, hangingUp); - } - } - } else if (CallResponse.class.equals(klass)) { - if (acquiringCallInfo.equals(state)) { - final CallResponse response = (CallResponse) message; - callInfo = response.get(); - fsm.transition(message, downloadingRcml); - } else if (acquiringCallMediaGroup.equals(state)) { - fsm.transition(message, checkingMediaGroupState); - } - } else if (DownloaderResponse.class.equals(klass)) { - downloaderResponse = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { - logger.debug("response succeeded " + downloaderResponse.succeeded() + ", statusCode " - + downloaderResponse.get().getStatusCode()); - } - if (downloaderResponse.succeeded() && HttpStatus.SC_OK == downloaderResponse.get().getStatusCode()) { - fsm.transition(message, acquiringCallMediaGroup); - } else if (downloaderResponse.succeeded() && HttpStatus.SC_NOT_FOUND == downloaderResponse.get().getStatusCode()) { - fsm.transition(message, notFound); - } - } else if (MediaGroupStateChanged.class.equals(klass)) { - final MediaGroupStateChanged event = (MediaGroupStateChanged) message; - if (MediaGroupStateChanged.State.ACTIVE == event.state()) { - if (initializingCallMediaGroup.equals(state) || checkingMediaGroupState.equals(state)) { - fsm.transition(message, ready); - } - if (ready.equals(state)) { - if (reject.equals(verb.name())) { - fsm.transition(message, playingRejectionPrompt); - } else if (fax.equals(verb.name())) { - fsm.transition(message, caching); - } else if (play.equals(verb.name())) { - fsm.transition(message, caching); - } else if (say.equals(verb.name())) { - fsm.transition(message, checkingCache); - } else if (gather.equals(verb.name())) { - fsm.transition(message, processingGatherChildren); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else if (hangup.equals(verb.name())) { - fsm.transition(message, hangingUp); - } else if (redirect.equals(verb.name())) { - fsm.transition(message, redirecting); - } else if (record.equals(verb.name())) { - fsm.transition(message, creatingRecording); - } else if (sms.equals(verb.name())) { - fsm.transition(message, creatingSmsSession); - } else { - invalidVerb(verb); - } - } - } else if (MediaGroupStateChanged.State.INACTIVE == event.state()) { - if (checkingMediaGroupState.equals(state)) { - fsm.transition(message, initializingCallMediaGroup); - } else if (!hangingUp.equals(state)) { - fsm.transition(message, hangingUp); - } - } - } - - else if (DiskCacheResponse.class.equals(klass)) { - final DiskCacheResponse response = (DiskCacheResponse) message; - if (response.succeeded()) { - if (caching.equals(state) || checkingCache.equals(state)) { - if (play.equals(verb.name()) || say.equals(verb.name())) { - fsm.transition(message, playing); - } else if (fax.equals(verb.name())) { - fsm.transition(message, faxing); - } - } else if (processingGatherChildren.equals(state)) { - fsm.transition(message, processingGatherChildren); - } - } else { - if (checkingCache.equals(state)) { - fsm.transition(message, synthesizing); - } else { - fsm.transition(message, hangingUp); - } - } - } else if (Tag.class.equals(klass)) { - verb = (Tag) message; - - if (Verbs.dial.equals(verb.name())) - originalInterpreter.tell(new Exception("Dial verb not supported"), source); - - if (reject.equals(verb.name())) { - fsm.transition(message, rejecting); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else if (fax.equals(verb.name())) { - fsm.transition(message, caching); - } else if (play.equals(verb.name())) { - fsm.transition(message, caching); - } else if (say.equals(verb.name())) { - fsm.transition(message, checkingCache); - } else if (gather.equals(verb.name())) { - fsm.transition(message, processingGatherChildren); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else if (hangup.equals(verb.name())) { - fsm.transition(message, hangingUp); - } else if (redirect.equals(verb.name())) { - fsm.transition(message, redirecting); - } else if (record.equals(verb.name())) { - fsm.transition(message, creatingRecording); - } else if (sms.equals(verb.name())) { - fsm.transition(message, creatingSmsSession); - } else { - invalidVerb(verb); - } - } else if (End.class.equals(klass)) { - if (!hangupOnEnd) { - originalInterpreter.tell(message, source); - } else { - fsm.transition(message, hangingUp); - } - } else if (StartGathering.class.equals(klass)) { - fsm.transition(message, gathering); - } else if (CallStateChanged.class.equals(klass)) { - final CallStateChanged event = (CallStateChanged) message; - if (CallStateChanged.State.NO_ANSWER == event.state() || CallStateChanged.State.COMPLETED == event.state() - || CallStateChanged.State.FAILED == event.state() || CallStateChanged.State.BUSY == event.state()) { - - originalInterpreter.tell(new Cancel(), source); - } - } else if (MediaGroupResponse.class.equals(klass)) { - final MediaGroupResponse response = (MediaGroupResponse) message; - if (response.succeeded()) { - if (playingRejectionPrompt.equals(state)) { - originalInterpreter.tell(message, source); - } else if (playing.equals(state)) { - fsm.transition(message, ready); - } else if (creatingRecording.equals(state)) { - fsm.transition(message, finishRecording); - } else if (gathering.equals(state)) { - fsm.transition(message, finishGathering); - } - } else { - originalInterpreter.tell(message, source); - } - } else if (SmsServiceResponse.class.equals(klass)) { - final SmsServiceResponse response = (SmsServiceResponse) message; - if (response.succeeded()) { - if (creatingSmsSession.equals(state)) { - fsm.transition(message, sendingSms); - } - } else { - fsm.transition(message, hangingUp); - } - } - // else if(AsrResponse.class.equals(klass)) { - // asrResponse(message); - // } - else if (SmsSessionResponse.class.equals(klass)) { - smsResponse(message); - } else if (FaxResponse.class.equals(klass)) { - fsm.transition(message, ready); - } else if (StopInterpreter.class.equals(klass)) { - if (CallStateChanged.State.IN_PROGRESS == callState) { - fsm.transition(message, hangingUp); - } else { - fsm.transition(message, finished); - } - } else if (message instanceof ReceiveTimeout) { - if (pausing.equals(state)) { - fsm.transition(message, ready); - } - } - } - - /* - * (non-Javadoc) - * @see org.mobicents.servlet.restcomm.interpreter.BaseVoiceInterpreter#parameters() - */ - List parameters() { - final List parameters = new ArrayList(); - final String callSid = callInfo.sid().toString(); - parameters.add(new BasicNameValuePair("CallSid", callSid)); - final String accountSid = accountId.toString(); - parameters.add(new BasicNameValuePair("AccountSid", accountSid)); - final String from = e164(callInfo.from()); - parameters.add(new BasicNameValuePair("From", from)); - final String to = e164(callInfo.to()); - parameters.add(new BasicNameValuePair("To", to)); - final String state = callState.toString(); - parameters.add(new BasicNameValuePair("CallStatus", state)); - parameters.add(new BasicNameValuePair("ApiVersion", version)); - final String direction = callInfo.direction(); - parameters.add(new BasicNameValuePair("Direction", direction)); - final String callerName = callInfo.fromName(); - parameters.add(new BasicNameValuePair("CallerName", callerName)); - final String forwardedFrom = callInfo.forwardedFrom(); - parameters.add(new BasicNameValuePair("ForwardedFrom", forwardedFrom)); - // Adding SIP OUT Headers and SipCallId for - // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out - if (CreateCall.Type.SIP == callInfo.type()) { - SipServletResponse lastResponse = callInfo.lastResponse(); - if (lastResponse != null) { - final int statusCode = lastResponse.getStatus(); - final String method = lastResponse.getMethod(); - // See https://www.twilio.com/docs/sip/receiving-sip-headers - // On a successful call setup (when a 200 OK SIP response is returned) any X-headers on the 200 OK message are - // posted to the call screening URL - if (statusCode >= 200 && statusCode < 300 && "INVITE".equalsIgnoreCase(method)) { - final String sipCallId = lastResponse.getCallId(); - parameters.add(new BasicNameValuePair("SipCallId", sipCallId)); - Iterator headerIt = lastResponse.getHeaderNames(); - while (headerIt.hasNext()) { - String headerName = headerIt.next(); - if (headerName.startsWith("X-")) { - parameters - .add(new BasicNameValuePair("SipHeader_" + headerName, lastResponse.getHeader(headerName))); - } - } - } - } - } - return parameters; - } - - private abstract class AbstractAction implements Action { - protected final ActorRef source; - - public AbstractAction(final ActorRef source) { - super(); - this.source = source; - } - } - - private final class AcquiringCallMediaGroup extends AbstractAction { - public AcquiringCallMediaGroup(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - call.tell(new CreateMediaGroup(), source); - } - } - - private final class CheckMediaGroupState extends AbstractAction { - public CheckMediaGroupState(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(Object message) throws Exception { - final Class klass = message.getClass(); - if (CallResponse.class.equals(klass)) { - final CallResponse response = (CallResponse) message; - callMediaGroup = response.get(); - // Ask CallMediaGroup to add us as Observer, if the callMediaGroup is active we will not reach - // InitializingCallMediaGroup where - // we were adding SubVoiceInterpreter as an observer. Better do it here. - callMediaGroup.tell(new Observe(source), source); - MediaGroupStatus status = new MediaGroupStatus(); - callMediaGroup.tell(status, source); - } - } - - } - - private final class InitializingCallMediaGroup extends AbstractAction { - public InitializingCallMediaGroup(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (MediaGroupStateChanged.class.equals(klass)) { - // final CallResponse response = (CallResponse)message; - // callMediaGroup = response.get(); - // callMediaGroup.tell(new Observe(source), source); - callMediaGroup.tell(new StartMediaGroup(), source); - } else if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - } - } - - private final class DownloadingRcml extends AbstractAction { - public DownloadingRcml(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - if (CallResponse.class.equals(klass)) { - final CallResponse response = (CallResponse) message; - callInfo = response.get(); - callState = callInfo.state(); - // Ask the downloader to get us the application that will be executed. - final List parameters = parameters(); - request = new HttpRequestDescriptor(url, method, parameters); - downloader.tell(request, source); - } - } - } - - private final class Ready extends AbstractAction { - public Ready(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final UntypedActorContext context = getContext(); - final State state = fsm.state(); - if (parser == null) { - response = downloaderResponse.get(); - - final String type = response.getContentType(); - if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - parser = parser(response.getContentAsString()); - } else if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { - parser = parser("" + request.getUri() + ""); - } else if (type.contains("text/plain")) { - parser = parser("" + response.getContentAsString() + ""); - } else { - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - - private final class NotFound extends AbstractAction { - public NotFound(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - final DownloaderResponse response = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { - logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); - } - final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " - + response.get().getURI()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - // Hang up the call. - call.tell(new org.mobicents.servlet.restcomm.telephony.NotFound(), source); - } - } - - private final class Rejecting extends AbstractAction { - public Rejecting(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - String reason = "rejected"; - Attribute attribute = verb.attribute("reason"); - if (attribute != null) { - reason = attribute.value(); - if (reason != null && !reason.isEmpty()) { - if ("rejected".equalsIgnoreCase(reason)) { - reason = "rejected"; - } else if ("busy".equalsIgnoreCase(reason)) { - reason = "busy"; - } else { - reason = "rejected"; - } - } else { - reason = "rejected"; - } - } - // Reject the call. - if ("rejected".equals(reason)) { - call.tell(new Answer(), source); - } else { - call.tell(new Reject(), source); - } - } - } - - private final class Finished extends AbstractAction { - public Finished(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallStateChanged.class.equals(klass)) { - final CallStateChanged event = (CallStateChanged) message; - callState = event.state(); - if (callRecord != null) { - callRecord = callRecord.setStatus(callState.toString()); - final DateTime end = DateTime.now(); - callRecord = callRecord.setEndTime(end); - final int seconds = (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000; - callRecord = callRecord.setDuration(seconds); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - records.updateCallDetailRecord(callRecord); - } - callback(); - } - // Cleanup the outbound call if necessary. - final State state = fsm.state(); - final StopMediaGroup stop = new StopMediaGroup(); - // Destroy the media group(s). - if (callMediaGroup != null) { - callMediaGroup.tell(stop, source); - final DestroyMediaGroup destroy = new DestroyMediaGroup(callMediaGroup); - call.tell(destroy, source); - callMediaGroup = null; - } - // Destroy the Call(s). - callManager.tell(new DestroyCall(call), source); - // Stop the dependencies. - final UntypedActorContext context = getContext(); - context.stop(mailer); - context.stop(downloader); - context.stop(asrService); - context.stop(faxService); - context.stop(cache); - context.stop(synthesizer); - // Stop the interpreter. - postCleanup(); - } - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreterBuilder.java deleted file mode 100644 index da311d1411..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SubVoiceInterpreterBuilder.java +++ /dev/null @@ -1,142 +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.mobicents.servlet.restcomm.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; - -import java.net.URI; - -import org.apache.commons.configuration.Configuration; - -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class SubVoiceInterpreterBuilder { - 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() { - return system.actorOf(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); - } - })); - } - - 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; - } -} \ No newline at end of file diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreter.java deleted file mode 100644 index f84887814c..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreter.java +++ /dev/null @@ -1,2109 +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.mobicents.servlet.restcomm.interpreter; - -import static akka.pattern.Patterns.ask; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.dial; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.fax; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.gather; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.hangup; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.pause; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.play; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.record; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.redirect; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.reject; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.say; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.sms; - -import java.io.IOException; -import java.math.BigDecimal; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Currency; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.servlet.sip.SipServletResponse; - -import org.apache.commons.configuration.Configuration; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.message.BasicNameValuePair; -import org.joda.time.DateTime; -import org.joda.time.Interval; -import org.mobicents.servlet.restcomm.asr.AsrResponse; -import org.mobicents.servlet.restcomm.cache.DiskCacheResponse; -import org.mobicents.servlet.restcomm.dao.CallDetailRecordsDao; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.fax.FaxResponse; -import org.mobicents.servlet.restcomm.fsm.Action; -import org.mobicents.servlet.restcomm.fsm.FiniteStateMachine; -import org.mobicents.servlet.restcomm.fsm.State; -import org.mobicents.servlet.restcomm.fsm.Transition; -import org.mobicents.servlet.restcomm.http.client.DownloaderResponse; -import org.mobicents.servlet.restcomm.http.client.HttpRequestDescriptor; -import org.mobicents.servlet.restcomm.interpreter.rcml.Attribute; -import org.mobicents.servlet.restcomm.interpreter.rcml.End; -import org.mobicents.servlet.restcomm.interpreter.rcml.GetNextVerb; -import org.mobicents.servlet.restcomm.interpreter.rcml.Nouns; -import org.mobicents.servlet.restcomm.interpreter.rcml.Tag; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.patterns.StopObserving; -import org.mobicents.servlet.restcomm.sms.SmsServiceResponse; -import org.mobicents.servlet.restcomm.sms.SmsSessionResponse; -import org.mobicents.servlet.restcomm.telephony.AddParticipant; -import org.mobicents.servlet.restcomm.telephony.Answer; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallManagerResponse; -import org.mobicents.servlet.restcomm.telephony.CallResponse; -import org.mobicents.servlet.restcomm.telephony.CallStateChanged; -import org.mobicents.servlet.restcomm.telephony.Cancel; -import org.mobicents.servlet.restcomm.telephony.ConferenceCenterResponse; -import org.mobicents.servlet.restcomm.telephony.ConferenceInfo; -import org.mobicents.servlet.restcomm.telephony.ConferenceModeratorPresent; -import org.mobicents.servlet.restcomm.telephony.ConferenceResponse; -import org.mobicents.servlet.restcomm.telephony.ConferenceStateChanged; -import org.mobicents.servlet.restcomm.telephony.CreateCall; -import org.mobicents.servlet.restcomm.telephony.CreateConference; -import org.mobicents.servlet.restcomm.telephony.CreateMediaGroup; -import org.mobicents.servlet.restcomm.telephony.CreateWaitUrlConfMediaGroup; -import org.mobicents.servlet.restcomm.telephony.DestroyCall; -import org.mobicents.servlet.restcomm.telephony.DestroyMediaGroup; -import org.mobicents.servlet.restcomm.telephony.Dial; -import org.mobicents.servlet.restcomm.telephony.GetCallInfo; -import org.mobicents.servlet.restcomm.telephony.GetConferenceInfo; -import org.mobicents.servlet.restcomm.telephony.Hangup; -import org.mobicents.servlet.restcomm.telephony.MediaGroupResponse; -import org.mobicents.servlet.restcomm.telephony.MediaGroupStateChanged; -import org.mobicents.servlet.restcomm.telephony.Mute; -import org.mobicents.servlet.restcomm.telephony.Play; -import org.mobicents.servlet.restcomm.telephony.Reject; -import org.mobicents.servlet.restcomm.telephony.RemoveParticipant; -import org.mobicents.servlet.restcomm.telephony.StartMediaGroup; -import org.mobicents.servlet.restcomm.telephony.StartRecordingCall; -import org.mobicents.servlet.restcomm.telephony.Stop; -import org.mobicents.servlet.restcomm.telephony.StopConference; -import org.mobicents.servlet.restcomm.telephony.StopMediaGroup; -import org.mobicents.servlet.restcomm.telephony.Unmute; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerResponse; -import org.mobicents.servlet.restcomm.util.UriUtils; - -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.Duration; -import akka.actor.ActorRef; -import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActorContext; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import akka.util.Timeout; - -/** - * @author thomas.quintana@telestax.com (Thomas Quintana) - * @author jean.deruelle@telestax.com - * @author gvagenas@telestax.com - * @author amit.bhayani@telestax.com (Amit Bhayani) - * @author pavel.slegr@telestax.com - */ -public final class VoiceInterpreter extends BaseVoiceInterpreter { - // Logger. - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - // States for the FSM. - private final State startDialing; - private final State processingDialChildren; - private final State acquiringOutboundCallInfo; - private final State forking; - private final State joiningCalls; - private final State bridged; - private final State finishDialing; - private final State acquiringConferenceInfo; - private final State acquiringConferenceMediaGroup; - private final State initializingConferenceMediaGroup; - private final State joiningConference; - private final State conferencing; - private final State finishConferencing; - private final State downloadingRcml; - private final State downloadingFallbackRcml; - private final State initializingCall; - private final State initializingCallMediaGroup; - private final State acquiringCallMediaGroup; - private final State ready; - private final State notFound; - private final State rejecting; - private final State finished; - - // FSM. - // The conference manager. - private final ActorRef conferenceManager; - - // State for outbound calls. - private boolean isForking; - private List dialBranches; - private List dialChildren; - private Map dialChildrenWithAttributes; - - // The conferencing stuff. - private ActorRef conference; - private ConferenceInfo conferenceInfo; - private ActorRef confInterpreter; - private ConferenceStateChanged.State conferenceState; - private boolean callMuted; - private boolean startConferenceOnEnter = true; - private ActorRef confSubVoiceInterpreter; - private ActorRef conferenceMediaGroup; - private Attribute dialRecordAttribute; - private boolean dialActionExecuted = false; - private ActorRef sender; - - 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 statusCallback, - final String statusCallbackMethod, final String emailAddress, final ActorRef callManager, - final ActorRef conferenceManager, final ActorRef sms, final DaoManager storage) { - super(); - final ActorRef source = self(); - acquiringCallMediaGroup = new State("acquiring call media group", new AcquiringCallMediaGroup(source), null); - downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); - downloadingFallbackRcml = new State("downloading fallback rcml", new DownloadingFallbackRcml(source), null); - initializingCall = new State("initializing call", new InitializingCall(source), null); - initializingCallMediaGroup = new State("initializing call media group", new InitializingCallMediaGroup(source), null); - ready = new State("ready", new Ready(source), null); - notFound = new State("notFound", new NotFound(source), null); - rejecting = new State("rejecting", new Rejecting(source), null); - startDialing = new State("start dialing", new StartDialing(source), null); - processingDialChildren = new State("processing dial children", new ProcessingDialChildren(source), null); - acquiringOutboundCallInfo = new State("acquiring outbound call info", new AcquiringOutboundCallInfo(source), null); - forking = new State("forking", new Forking(source), null); - joiningCalls = new State("joining calls", new JoiningCalls(source), null); - bridged = new State("bridged", new Bridged(source), null); - finishDialing = new State("finish dialing", new FinishDialing(source), null); - acquiringConferenceInfo = new State("acquiring conference info", new AcquiringConferenceInfo(source), null); - acquiringConferenceMediaGroup = new State("acquiring conference media group", - new AcquiringConferenceMediaGroup(source), null); - initializingConferenceMediaGroup = new State("initializing conference media group", - new InitializingConferenceMediaGroup(source), null); - joiningConference = new State("joining conference", new JoiningConference(source), null); - conferencing = new State("conferencing", new Conferencing(source), null); - finishConferencing = new State("finish conferencing", new FinishConferencing(source), null); - finished = new State("finished", new Finished(source), null); - /* - * dialing = new State("dialing", null, null); bridging = new State("bridging", null, null); conferencing = new - * State("conferencing", null, null); - */ - transitions.add(new Transition(acquiringAsrInfo, finished)); - transitions.add(new Transition(acquiringSynthesizerInfo, finished)); - transitions.add(new Transition(acquiringCallInfo, initializingCall)); - transitions.add(new Transition(acquiringCallInfo, downloadingRcml)); - transitions.add(new Transition(acquiringCallInfo, finished)); - transitions.add(new Transition(acquiringCallInfo, acquiringCallMediaGroup)); - transitions.add(new Transition(initializingCall, acquiringCallMediaGroup)); - transitions.add(new Transition(initializingCall, hangingUp)); - transitions.add(new Transition(initializingCall, finished)); - transitions.add(new Transition(acquiringCallMediaGroup, initializingCallMediaGroup)); - transitions.add(new Transition(acquiringCallMediaGroup, hangingUp)); - transitions.add(new Transition(acquiringCallMediaGroup, finished)); - transitions.add(new Transition(initializingCallMediaGroup, faxing)); - transitions.add(new Transition(initializingCallMediaGroup, downloadingRcml)); - transitions.add(new Transition(initializingCallMediaGroup, playingRejectionPrompt)); - transitions.add(new Transition(initializingCallMediaGroup, pausing)); - transitions.add(new Transition(initializingCallMediaGroup, checkingCache)); - transitions.add(new Transition(initializingCallMediaGroup, caching)); - transitions.add(new Transition(initializingCallMediaGroup, synthesizing)); - transitions.add(new Transition(initializingCallMediaGroup, redirecting)); - transitions.add(new Transition(initializingCallMediaGroup, processingGatherChildren)); - transitions.add(new Transition(initializingCallMediaGroup, creatingRecording)); - transitions.add(new Transition(initializingCallMediaGroup, creatingSmsSession)); - transitions.add(new Transition(initializingCallMediaGroup, startDialing)); - transitions.add(new Transition(initializingCallMediaGroup, hangingUp)); - transitions.add(new Transition(initializingCallMediaGroup, finished)); - transitions.add(new Transition(downloadingRcml, ready)); - transitions.add(new Transition(downloadingRcml, notFound)); - transitions.add(new Transition(downloadingRcml, downloadingFallbackRcml)); - transitions.add(new Transition(downloadingRcml, hangingUp)); - transitions.add(new Transition(downloadingRcml, finished)); - transitions.add(new Transition(downloadingFallbackRcml, ready)); - transitions.add(new Transition(downloadingFallbackRcml, hangingUp)); - transitions.add(new Transition(downloadingFallbackRcml, finished)); - transitions.add(new Transition(ready, initializingCall)); - transitions.add(new Transition(ready, faxing)); - transitions.add(new Transition(ready, pausing)); - transitions.add(new Transition(ready, checkingCache)); - transitions.add(new Transition(ready, caching)); - transitions.add(new Transition(ready, synthesizing)); - transitions.add(new Transition(ready, rejecting)); - transitions.add(new Transition(ready, redirecting)); - transitions.add(new Transition(ready, processingGatherChildren)); - transitions.add(new Transition(ready, creatingRecording)); - transitions.add(new Transition(ready, creatingSmsSession)); - transitions.add(new Transition(ready, startDialing)); - transitions.add(new Transition(ready, hangingUp)); - transitions.add(new Transition(ready, finished)); - transitions.add(new Transition(pausing, ready)); - transitions.add(new Transition(pausing, finished)); - transitions.add(new Transition(rejecting, acquiringCallMediaGroup)); - transitions.add(new Transition(rejecting, finished)); - transitions.add(new Transition(faxing, ready)); - transitions.add(new Transition(faxing, finished)); - transitions.add(new Transition(caching, finished)); - transitions.add(new Transition(playing, ready)); - transitions.add(new Transition(playing, finished)); - transitions.add(new Transition(synthesizing, finished)); - transitions.add(new Transition(redirecting, ready)); - transitions.add(new Transition(redirecting, finished)); - transitions.add(new Transition(creatingRecording, finished)); - transitions.add(new Transition(finishRecording, ready)); - transitions.add(new Transition(finishRecording, finished)); - transitions.add(new Transition(processingGatherChildren, finished)); - transitions.add(new Transition(gathering, finished)); - transitions.add(new Transition(finishGathering, ready)); - transitions.add(new Transition(finishGathering, finished)); - transitions.add(new Transition(creatingSmsSession, finished)); - transitions.add(new Transition(sendingSms, ready)); - transitions.add(new Transition(sendingSms, finished)); - transitions.add(new Transition(startDialing, processingDialChildren)); - transitions.add(new Transition(startDialing, acquiringConferenceInfo)); - transitions.add(new Transition(startDialing, faxing)); - transitions.add(new Transition(startDialing, pausing)); - transitions.add(new Transition(startDialing, checkingCache)); - transitions.add(new Transition(startDialing, caching)); - transitions.add(new Transition(startDialing, synthesizing)); - transitions.add(new Transition(startDialing, redirecting)); - transitions.add(new Transition(startDialing, processingGatherChildren)); - transitions.add(new Transition(startDialing, creatingRecording)); - transitions.add(new Transition(startDialing, creatingSmsSession)); - transitions.add(new Transition(startDialing, startDialing)); - transitions.add(new Transition(startDialing, hangingUp)); - transitions.add(new Transition(startDialing, finished)); - transitions.add(new Transition(processingDialChildren, processingDialChildren)); - transitions.add(new Transition(processingDialChildren, forking)); - transitions.add(new Transition(processingDialChildren, hangingUp)); - transitions.add(new Transition(processingDialChildren, finished)); - transitions.add(new Transition(forking, acquiringOutboundCallInfo)); - transitions.add(new Transition(forking, finishDialing)); - transitions.add(new Transition(forking, hangingUp)); - transitions.add(new Transition(forking, finished)); - transitions.add(new Transition(acquiringOutboundCallInfo, joiningCalls)); - transitions.add(new Transition(acquiringOutboundCallInfo, hangingUp)); - transitions.add(new Transition(acquiringOutboundCallInfo, finished)); - transitions.add(new Transition(joiningCalls, bridged)); - transitions.add(new Transition(joiningCalls, hangingUp)); - transitions.add(new Transition(joiningCalls, finished)); - transitions.add(new Transition(bridged, finishDialing)); - transitions.add(new Transition(bridged, hangingUp)); - transitions.add(new Transition(bridged, finished)); - transitions.add(new Transition(finishDialing, ready)); - transitions.add(new Transition(finishDialing, faxing)); - transitions.add(new Transition(finishDialing, pausing)); - transitions.add(new Transition(finishDialing, checkingCache)); - transitions.add(new Transition(finishDialing, caching)); - transitions.add(new Transition(finishDialing, synthesizing)); - transitions.add(new Transition(finishDialing, redirecting)); - transitions.add(new Transition(finishDialing, processingGatherChildren)); - transitions.add(new Transition(finishDialing, creatingRecording)); - transitions.add(new Transition(finishDialing, creatingSmsSession)); - transitions.add(new Transition(finishDialing, startDialing)); - transitions.add(new Transition(finishDialing, hangingUp)); - transitions.add(new Transition(finishDialing, finished)); - transitions.add(new Transition(acquiringConferenceInfo, acquiringConferenceMediaGroup)); - transitions.add(new Transition(acquiringConferenceInfo, hangingUp)); - transitions.add(new Transition(acquiringConferenceInfo, finished)); - transitions.add(new Transition(acquiringConferenceMediaGroup, initializingConferenceMediaGroup)); - transitions.add(new Transition(acquiringConferenceMediaGroup, faxing)); - transitions.add(new Transition(acquiringConferenceMediaGroup, pausing)); - transitions.add(new Transition(acquiringConferenceMediaGroup, checkingCache)); - transitions.add(new Transition(acquiringConferenceMediaGroup, caching)); - transitions.add(new Transition(acquiringConferenceMediaGroup, synthesizing)); - transitions.add(new Transition(acquiringConferenceMediaGroup, redirecting)); - transitions.add(new Transition(acquiringConferenceMediaGroup, processingGatherChildren)); - transitions.add(new Transition(acquiringConferenceMediaGroup, creatingRecording)); - transitions.add(new Transition(acquiringConferenceMediaGroup, creatingSmsSession)); - transitions.add(new Transition(acquiringConferenceMediaGroup, startDialing)); - transitions.add(new Transition(acquiringConferenceMediaGroup, hangingUp)); - transitions.add(new Transition(acquiringConferenceMediaGroup, finished)); - transitions.add(new Transition(initializingConferenceMediaGroup, joiningConference)); - transitions.add(new Transition(initializingConferenceMediaGroup, hangingUp)); - transitions.add(new Transition(initializingConferenceMediaGroup, finished)); - transitions.add(new Transition(joiningConference, conferencing)); - transitions.add(new Transition(joiningConference, hangingUp)); - transitions.add(new Transition(joiningConference, finished)); - transitions.add(new Transition(conferencing, finishConferencing)); - transitions.add(new Transition(conferencing, hangingUp)); - transitions.add(new Transition(conferencing, finished)); - transitions.add(new Transition(finishConferencing, ready)); - transitions.add(new Transition(finishConferencing, faxing)); - transitions.add(new Transition(finishConferencing, pausing)); - transitions.add(new Transition(finishConferencing, checkingCache)); - transitions.add(new Transition(finishConferencing, caching)); - transitions.add(new Transition(finishConferencing, synthesizing)); - transitions.add(new Transition(finishConferencing, redirecting)); - transitions.add(new Transition(finishConferencing, processingGatherChildren)); - transitions.add(new Transition(finishConferencing, creatingRecording)); - transitions.add(new Transition(finishConferencing, creatingSmsSession)); - transitions.add(new Transition(finishConferencing, startDialing)); - transitions.add(new Transition(finishConferencing, hangingUp)); - transitions.add(new Transition(finishConferencing, finished)); - transitions.add(new Transition(hangingUp, finished)); - transitions.add(new Transition(hangingUp, finishDialing)); - // 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.callManager = callManager; - this.conferenceManager = conferenceManager; - this.asrService = asr(configuration.subset("speech-recognizer")); - this.faxService = fax(configuration.subset("fax-service")); - this.smsService = sms; - this.smsSessions = new HashMap(); - this.storage = storage; - this.synthesizer = tts(configuration.subset("speech-synthesizer")); - this.mailer = mailer(configuration.subset("smtp")); - final Configuration runtime = configuration.subset("runtime-settings"); - String path = runtime.getString("cache-path"); - if (!path.endsWith("/")) { - path = path + "/"; - } - path = path + accountId.toString(); - cachePath = path; - String uri = runtime.getString("cache-uri"); - if (!uri.endsWith("/")) { - uri = uri + "/"; - } - uri = uri + accountId.toString(); - this.cache = cache(path, uri); - this.downloader = downloader(); - } - - 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); - builder.setSid(sid); - builder.setAccountSid(accountId); - builder.setCallSid(callInfo.sid()); - builder.setApiVersion(version); - builder.setLog(log); - builder.setErrorCode(error); - final String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); - StringBuilder buffer = new StringBuilder(); - buffer.append(base); - if (!base.endsWith("/")) { - buffer.append("/"); - } - buffer.append(error).append(".html"); - final URI info = URI.create(buffer.toString()); - builder.setMoreInfo(info); - builder.setMessageText(message); - final DateTime now = DateTime.now(); - builder.setMessageDate(now); - if (request != null) { - builder.setRequestUrl(request.getUri()); - builder.setRequestMethod(request.getMethod()); - builder.setRequestVariables(request.getParametersAsString()); - } - if (response != null) { - builder.setResponseHeaders(response.getHeadersAsString()); - final String type = response.getContentType(); - if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - try { - builder.setResponseBody(response.getContentAsString()); - } catch (final IOException exception) { - logger.error( - "There was an error while reading the contents of the resource " + "located @ " + url.toString(), - exception); - } - } - } - buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/"); - buffer.append(accountId.toString()).append("/Notifications/"); - buffer.append(sid.toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - return builder.build(); - } - - @SuppressWarnings("unchecked") - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - final State state = fsm.state(); - sender = sender(); - if (logger.isInfoEnabled()) { - logger.info(" ********** VoiceInterpreter's Current State: " + state.toString()); - logger.info(" ********** VoiceInterpreter's Processing Message: " + klass.getName()); - } - if (StartInterpreter.class.equals(klass)) { - fsm.transition(message, acquiringAsrInfo); - } else if (AsrResponse.class.equals(klass)) { - if (outstandingAsrRequests > 0) { - asrResponse(message); - } else { - fsm.transition(message, acquiringSynthesizerInfo); - } - } else if (SpeechSynthesizerResponse.class.equals(klass)) { - if (acquiringSynthesizerInfo.equals(state)) { - fsm.transition(message, acquiringCallInfo); - } else if (synthesizing.equals(state)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - if (response.succeeded()) { - fsm.transition(message, caching); - } else { - fsm.transition(message, hangingUp); - } - } else if (processingGatherChildren.equals(state)) { - final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; - if (response.succeeded()) { - fsm.transition(message, processingGatherChildren); - } else { - fsm.transition(message, hangingUp); - } - } - } else if (CallResponse.class.equals(klass)) { - if (forking.equals(state)) { - // Allow updating of the callInfo at the VoiceInterpreter so that we can do Dial SIP Screening - // (https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out) accurately from latest - // response received - final CallResponse response = (CallResponse) message; - //Check from whom is the message (initial call or outbound call) and update info accordingly - if(sender == call) { - callInfo = response.get(); - } else { - outboundCallInfo = response.get(); - } - } else if (acquiringCallInfo.equals(state)) { - final CallResponse response = (CallResponse) message; - //Check from whom is the message (initial call or outbound call) and update info accordingly - if(sender == call) { - callInfo = response.get(); - } else { - outboundCallInfo = response.get(); - } - final String direction = callInfo.direction(); - if ("inbound".equals(direction)) { - fsm.transition(message, downloadingRcml); - } else { - fsm.transition(message, initializingCall); - } - } else if (acquiringCallMediaGroup.equals(state)) { - fsm.transition(message, initializingCallMediaGroup); - } else if (acquiringOutboundCallInfo.equals(state)) { - fsm.transition(message, joiningCalls); - } - } else if (CallStateChanged.class.equals(klass)) { - final CallStateChanged event = (CallStateChanged) message; - callState = event.state(); - if (CallStateChanged.State.RINGING == event.state()) { - if (forking.equals(state)) { - outboundCall = sender; - } - // update db and callback statusCallback url. - } else if (CallStateChanged.State.IN_PROGRESS == event.state()) { - if (initializingCall.equals(state) || rejecting.equals(state)) { - fsm.transition(message, acquiringCallMediaGroup); - } else if (joiningConference.equals(state)) { - fsm.transition(message, conferencing); - } else if (forking.equals(state)) { - if(outboundCall == null) - outboundCall = sender; - fsm.transition(message, acquiringOutboundCallInfo); - } else if (joiningCalls.equals(state)) { - fsm.transition(message, bridged); - } - } else if (CallStateChanged.State.NO_ANSWER == event.state() || CallStateChanged.State.COMPLETED == event.state() - || CallStateChanged.State.FAILED == event.state()) { - // changed for https://bitbucket.org/telestax/telscale-restcomm/issue/132/ so that we can do Dial SIP Screening - if ((bridged.equals(state) || forking.equals(state)) && (sender == outboundCall || outboundCall == null)) { - fsm.transition(message, finishDialing ); - } else if (creatingRecording.equals(state)) { - //Ask callMediaGroup to stop recording so we have the recording file available - //Issue #197: https://telestax.atlassian.net/browse/RESTCOMM-197 - callMediaGroup.tell(new Stop(), null); - fsm.transition(message, finishRecording); - } else if (bridged.equals(state) && call == sender()) { - if(!dialActionExecuted) { - fsm.transition(message, finishDialing); - } - } else { - if (!finishDialing.equals(state)) - fsm.transition(message, finished); - } - // else if (!forking.equals(state) || call == sender()) { - // fsm.transition(message, finished); - // } - } else if (CallStateChanged.State.BUSY == event.state()) { - fsm.transition(message, finishDialing); - } - } else if (CallManagerResponse.class.equals(klass)) { - final CallManagerResponse response = (CallManagerResponse) message; - if (response.succeeded()) { - if (startDialing.equals(state)) { - fsm.transition(message, processingDialChildren); - } else if (processingDialChildren.equals(state)) { - fsm.transition(message, processingDialChildren); - } - } else { - if (state.equals(processingDialChildren)) { - executeDialAction(message, outboundCall); - } - fsm.transition(message, hangingUp); - } - } else if (StartForking.class.equals(klass)) { - fsm.transition(message, processingDialChildren); - } else if (ConferenceCenterResponse.class.equals(klass)) { - if (startDialing.equals(state)) { - fsm.transition(message, acquiringConferenceInfo); - } - } else if (Fork.class.equals(klass)) { - if (processingDialChildren.equals(state)) { - fsm.transition(message, forking); - } - } else if (ConferenceResponse.class.equals(klass)) { - if (acquiringConferenceInfo.equals(state)) { - fsm.transition(message, acquiringConferenceMediaGroup); - } else if (acquiringConferenceMediaGroup.equals(state)) { - fsm.transition(message, initializingConferenceMediaGroup); - } - } else if (ConferenceStateChanged.class.equals(klass)) { - final ConferenceStateChanged event = (ConferenceStateChanged) message; - if (ConferenceStateChanged.State.COMPLETED == event.state()) { - if (conferencing.equals(state)) { - fsm.transition(message, finishConferencing); - } - } else if (ConferenceStateChanged.State.RUNNING_MODERATOR_PRESENT == event.state()) { - conferenceState = event.state(); - conferenceStateModeratorPresent(message); - } - } else if (DownloaderResponse.class.equals(klass)) { - final DownloaderResponse response = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { - logger.debug("Rcml URI : " + response.get().getURI() + "response succeeded " + response.succeeded() - + ", statusCode " + response.get().getStatusCode()); - } - if (response.succeeded() && HttpStatus.SC_OK == response.get().getStatusCode()) { - fsm.transition(message, ready); - } else if (response.succeeded() && HttpStatus.SC_NOT_FOUND == response.get().getStatusCode()) { - fsm.transition(message, notFound); - } else { - if (downloadingRcml.equals(state)) { - if (fallbackUrl != null) { - fsm.transition(message, downloadingFallbackRcml); - } else { - fsm.transition(message, finished); - } - } else { - fsm.transition(message, finished); - } - } - } else if (DiskCacheResponse.class.equals(klass)) { - final DiskCacheResponse response = (DiskCacheResponse) message; - if (response.succeeded()) { - if (caching.equals(state) || checkingCache.equals(state)) { - if (play.equals(verb.name()) || say.equals(verb.name())) { - fsm.transition(message, playing); - } else if (fax.equals(verb.name())) { - fsm.transition(message, faxing); - } - } else if (processingGatherChildren.equals(state)) { - fsm.transition(message, processingGatherChildren); - } - } else { - if (logger.isDebugEnabled()) { - logger.debug("DiskCacheResponse is " + response.toString()); - } - if (checkingCache.equals(state)) { - fsm.transition(message, synthesizing); - } else { - fsm.transition(message, hangingUp); - } - } - } else if (Tag.class.equals(klass)) { - final Tag verb = (Tag) message; - if (CallStateChanged.State.RINGING == callState) { - if (reject.equals(verb.name())) { - fsm.transition(message, rejecting); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else { - fsm.transition(message, initializingCall); - } - } else if (dial.equals(verb.name())) { - dialRecordAttribute = verb.attribute("record"); - fsm.transition(message, startDialing); - } else if (fax.equals(verb.name())) { - fsm.transition(message, caching); - } else if (play.equals(verb.name())) { - fsm.transition(message, caching); - } else if (say.equals(verb.name())) { - // fsm.transition(message, synthesizing); - fsm.transition(message, checkingCache); - } else if (gather.equals(verb.name())) { - fsm.transition(message, processingGatherChildren); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else if (hangup.equals(verb.name())) { - fsm.transition(message, hangingUp); - } else if (redirect.equals(verb.name())) { - fsm.transition(message, redirecting); - } else if (record.equals(verb.name())) { - fsm.transition(message, creatingRecording); - } else if (sms.equals(verb.name())) { - fsm.transition(message, creatingSmsSession); - } else { - invalidVerb(verb); - } - } else if (End.class.equals(klass)) { - fsm.transition(message, hangingUp); - } else if (StartGathering.class.equals(klass)) { - fsm.transition(message, gathering); - } else if (MediaGroupStateChanged.class.equals(klass)) { - final MediaGroupStateChanged event = (MediaGroupStateChanged) message; - if (MediaGroupStateChanged.State.ACTIVE == event.state()) { - if (initializingCallMediaGroup.equals(state)) { - final String direction = callInfo.direction(); - if ("inbound".equals(direction)) { - if (reject.equals(verb.name())) { - fsm.transition(message, playingRejectionPrompt); - } else if (dial.equals(verb.name())) { - dialRecordAttribute = verb.attribute("record"); - fsm.transition(message, startDialing); - } else if (fax.equals(verb.name())) { - fsm.transition(message, caching); - } else if (play.equals(verb.name())) { - fsm.transition(message, caching); - } else if (say.equals(verb.name())) { - // fsm.transition(message, synthesizing); - fsm.transition(message, checkingCache); - } else if (gather.equals(verb.name())) { - fsm.transition(message, processingGatherChildren); - } else if (pause.equals(verb.name())) { - fsm.transition(message, pausing); - } else if (hangup.equals(verb.name())) { - fsm.transition(message, hangingUp); - } else if (redirect.equals(verb.name())) { - fsm.transition(message, redirecting); - } else if (record.equals(verb.name())) { - fsm.transition(message, creatingRecording); - } else if (sms.equals(verb.name())) { - fsm.transition(message, creatingSmsSession); - } else { - invalidVerb(verb); - } - } else { - fsm.transition(message, downloadingRcml); - } - } else if (initializingConferenceMediaGroup.equals(state)) { - fsm.transition(message, joiningConference); - } else if (bridged.equals(state)) { - if (dialRecordAttribute != null && dialRecordAttribute.value().equalsIgnoreCase("true")) - recordCall(); - } - } else if (MediaGroupStateChanged.State.INACTIVE == event.state()) { - if (!hangingUp.equals(state)) { - fsm.transition(message, hangingUp); - } - } - } else if (MediaGroupResponse.class.equals(klass)) { - final MediaGroupResponse response = (MediaGroupResponse) message; - if (response.succeeded()) { - if (playingRejectionPrompt.equals(state)) { - fsm.transition(message, hangingUp); - } else if (playing.equals(state)) { - fsm.transition(message, ready); - } else if (creatingRecording.equals(state)) { - fsm.transition(message, finishRecording); - } else if (gathering.equals(state)) { - fsm.transition(message, finishGathering); - } else if (initializingConferenceMediaGroup.equals(state)) { - fsm.transition(message, joiningConference); - } - } else { - fsm.transition(message, hangingUp); - } - } else if (SmsServiceResponse.class.equals(klass)) { - final SmsServiceResponse response = (SmsServiceResponse) message; - if (response.succeeded()) { - if (creatingSmsSession.equals(state)) { - fsm.transition(message, sendingSms); - } - } else { - fsm.transition(message, hangingUp); - } - } - // else if(AsrResponse.class.equals(klass)) { - // asrResponse(message); - // } - else if (SmsSessionResponse.class.equals(klass)) { - smsResponse(message); - } else if (FaxResponse.class.equals(klass)) { - fsm.transition(message, ready); - } else if (StopInterpreter.class.equals(klass)) { - if (CallStateChanged.State.IN_PROGRESS == callState) { - fsm.transition(message, hangingUp); - } else { - fsm.transition(message, finished); - } - } else if (message instanceof ReceiveTimeout) { - if (pausing.equals(state)) { - fsm.transition(message, ready); - } else if (conferencing.equals(state)) { - fsm.transition(message, finishConferencing); - } else if (forking.equals(state)) { - fsm.transition(message, finishDialing); - } else if (bridged.equals(state)) { - fsm.transition(message, finishDialing); - } - } - } - - private void conferenceStateModeratorPresent(final Object message) { - if (!startConferenceOnEnter && !callMuted) { - logger.info("VoiceInterpreter#conferenceStateModeratorPresent will unmute the call"); - call.tell(new Unmute(), self()); - } - - if (confSubVoiceInterpreter != null) { - logger.info("VoiceInterpreter stopping confSubVoiceInterpreter"); - - // Stop the conference back ground music - final StopInterpreter stop = StopInterpreter.instance(); - confSubVoiceInterpreter.tell(stop, self()); - } - } - - List parameters() { - final List parameters = new ArrayList(); - final String callSid = callInfo.sid().toString(); - parameters.add(new BasicNameValuePair("CallSid", callSid)); - final String accountSid = accountId.toString(); - parameters.add(new BasicNameValuePair("AccountSid", accountSid)); - final String from = e164(callInfo.from()); - parameters.add(new BasicNameValuePair("From", from)); - final String to = e164(callInfo.to()); - parameters.add(new BasicNameValuePair("To", to)); - final String state = callState.toString(); - parameters.add(new BasicNameValuePair("CallStatus", state)); - parameters.add(new BasicNameValuePair("ApiVersion", version)); - final String direction = callInfo.direction(); - parameters.add(new BasicNameValuePair("Direction", direction)); - final String callerName = callInfo.fromName(); - parameters.add(new BasicNameValuePair("CallerName", callerName)); - final String forwardedFrom = callInfo.forwardedFrom(); - parameters.add(new BasicNameValuePair("ForwardedFrom", forwardedFrom)); - // logger.info("Type " + callInfo.type()); - if (CreateCall.Type.SIP == callInfo.type()) { - // Adding SIP OUT Headers and SipCallId for - // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out - SipServletResponse lastResponse = callInfo.lastResponse(); - // logger.info("lastResponse " + lastResponse); - if (lastResponse != null) { - final int statusCode = lastResponse.getStatus(); - final String method = lastResponse.getMethod(); - // See https://www.twilio.com/docs/sip/receiving-sip-headers - // Headers on the final SIP response message (any 4xx or 5xx message or the final BYE/200) are posted to the - // Dial action URL. - if ((statusCode >= 400 && "INVITE".equalsIgnoreCase(method)) - || (statusCode >= 200 && statusCode < 300 && "BYE".equalsIgnoreCase(method))) { - final String sipCallId = lastResponse.getCallId(); - parameters.add(new BasicNameValuePair("DialSipCallId", sipCallId)); - parameters.add(new BasicNameValuePair("DialSipResponseCode", "" + statusCode)); - Iterator headerIt = lastResponse.getHeaderNames(); - while (headerIt.hasNext()) { - String headerName = headerIt.next(); - if (headerName.startsWith("X-")) { - parameters.add(new BasicNameValuePair("DialSipHeader_" + headerName, lastResponse - .getHeader(headerName))); - } - } - } - } - } - return parameters; - } - - private abstract class AbstractAction implements Action { - protected final ActorRef source; - - public AbstractAction(final ActorRef source) { - super(); - this.source = source; - } - } - - private final class InitializingCall extends AbstractAction { - public InitializingCall(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallResponse.class.equals(klass)) { - // Update the interpreter state. - final CallResponse response = (CallResponse) message; - callInfo = response.get(); - callState = callInfo.state(); - if (callState.name().equalsIgnoreCase(CallStateChanged.State.IN_PROGRESS.name())) { - final CallStateChanged event = new CallStateChanged(CallStateChanged.State.IN_PROGRESS); - source.tell(event, source); - // fsm.transition(event, acquiringCallMediaGroup); - return; - } - // Update the storage. - if (callRecord != null) { - callRecord = callRecord.setStatus(callState.toString()); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - records.updateCallDetailRecord(callRecord); - } - // Update the application. - callback(); - // Start dialing. - call.tell(new Dial(), source); - } else if (Tag.class.equals(klass)) { - // Update the interpreter state. - verb = (Tag) message; - // Answer the call. - call.tell(new Answer(), source); - } - } - } - - private final class AcquiringCallMediaGroup extends AbstractAction { - public AcquiringCallMediaGroup(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallStateChanged.class.equals(klass)) { - // Update the interpreter state. - final CallStateChanged event = (CallStateChanged) message; - callState = event.state(); - // Update the storage. - if (callRecord != null) { - callRecord = callRecord.setStatus(callState.toString()); - callRecord = callRecord.setStartTime(DateTime.now()); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - records.updateCallDetailRecord(callRecord); - } - // Update the application. - callback(); - } - call.tell(new CreateMediaGroup(), source); - } - } - - private final class InitializingCallMediaGroup extends AbstractAction { - public InitializingCallMediaGroup(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallResponse.class.equals(klass)) { - final CallResponse response = (CallResponse) message; - callMediaGroup = response.get(); - callMediaGroup.tell(new Observe(source), source); - callMediaGroup.tell(new StartMediaGroup(), source); - } else if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - } - } - - private final class DownloadingRcml extends AbstractAction { - public DownloadingRcml(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - if (CallResponse.class.equals(klass)) { - final CallResponse response = (CallResponse) message; - callInfo = response.get(); - callState = callInfo.state(); - if (callInfo.direction().equals("inbound")) { - // Create a call detail record for the call. - final CallDetailRecord.Builder builder = CallDetailRecord.builder(); - builder.setSid(callInfo.sid()); - builder.setDateCreated(callInfo.dateCreated()); - builder.setAccountSid(accountId); - builder.setTo(callInfo.to()); - builder.setCallerName(callInfo.fromName()); - builder.setFrom(callInfo.from()); - builder.setForwardedFrom(callInfo.forwardedFrom()); - builder.setPhoneNumberSid(phoneId); - builder.setStatus(callState.toString()); - final DateTime now = DateTime.now(); - builder.setStartTime(now); - builder.setDirection(callInfo.direction()); - builder.setApiVersion(version); - builder.setPrice(new BigDecimal("0.00")); - // TODO implement currency property to be read from Configuration - builder.setPriceUnit(Currency.getInstance("USD")); - final StringBuilder buffer = new StringBuilder(); - buffer.append("/").append(version).append("/Accounts/"); - buffer.append(accountId.toString()).append("/Calls/"); - buffer.append(callInfo.sid().toString()); - final URI uri = URI.create(buffer.toString()); - builder.setUri(uri); - - builder.setCallPath(call.path().toString()); - - callRecord = builder.build(); - records.addCallDetailRecord(callRecord); - // Update the application. - callback(); - } - } - // Ask the downloader to get us the application that will be executed. - final List parameters = parameters(); - request = new HttpRequestDescriptor(url, method, parameters); - downloader.tell(request, source); - } - } - - private final class DownloadingFallbackRcml extends AbstractAction { - public DownloadingFallbackRcml(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - // Notify the account of the issue. - if (DownloaderResponse.class.equals(klass)) { - final DownloaderResponse result = (DownloaderResponse) message; - final Throwable cause = result.cause(); - Notification notification = null; - if (cause instanceof ClientProtocolException) { - notification = notification(ERROR_NOTIFICATION, 11206, cause.getMessage()); - } else if (cause instanceof IOException) { - notification = notification(ERROR_NOTIFICATION, 11205, cause.getMessage()); - } else if (cause instanceof URISyntaxException) { - notification = notification(ERROR_NOTIFICATION, 11100, cause.getMessage()); - } - if (notification != null) { - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - sendMail(notification); - } - } - // Try to use the fall back url and method. - final List parameters = parameters(); - request = new HttpRequestDescriptor(fallbackUrl, fallbackMethod, parameters); - downloader.tell(request, source); - } - } - - private final class Ready extends AbstractAction { - public Ready(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final UntypedActorContext context = getContext(); - final State state = fsm.state(); - if (initializingCallMediaGroup.equals(state)) { - // Handle pending verbs. - source.tell(verb, source); - return; - } else if (downloadingRcml.equals(state) || downloadingFallbackRcml.equals(state) || redirecting.equals(state) - || finishGathering.equals(state) || finishRecording.equals(state) || sendingSms.equals(state) - || finishDialing.equals(state) || finishConferencing.equals(state)) { - response = ((DownloaderResponse) message).get(); - if (parser != null) { - context.stop(parser); - parser = null; - } - final String type = response.getContentType(); - if(type != null) { - if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - parser = parser(response.getContentAsString()); - } else if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { - parser = parser("" + request.getUri() + ""); - } else if (type.contains("text/plain")) { - parser = parser("" + response.getContentAsString() + ""); - } - } else { - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - } else if (pausing.equals(state)) { - context.setReceiveTimeout(Duration.Undefined()); - } - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - - private final class NotFound extends AbstractAction { - public NotFound(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - final DownloaderResponse response = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { - logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); - } - final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " - + response.get().getURI()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - // Hang up the call. - call.tell(new org.mobicents.servlet.restcomm.telephony.NotFound(), source); - } - } - - private final class Rejecting extends AbstractAction { - public Rejecting(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - String reason = "rejected"; - Attribute attribute = verb.attribute("reason"); - if (attribute != null) { - reason = attribute.value(); - if (reason != null && !reason.isEmpty()) { - if ("rejected".equalsIgnoreCase(reason)) { - reason = "rejected"; - } else if ("busy".equalsIgnoreCase(reason)) { - reason = "busy"; - } else { - reason = "rejected"; - } - } else { - reason = "rejected"; - } - } - // Reject the call. - if ("rejected".equals(reason)) { - call.tell(new Answer(), source); - } else { - call.tell(new Reject(), source); - } - } - } - - private abstract class AbstractDialAction extends AbstractAction { - public AbstractDialAction(final ActorRef source) { - super(source); - } - - protected String callerId(final Tag container) { - // Parse "from". - String callerId = null; - - //Issue 210: https://telestax.atlassian.net/browse/RESTCOMM-210 - final boolean useInitialFromAsCallerId = configuration.subset("runtime-settings").getBoolean("from-address-to-proxied-calls"); - if(useInitialFromAsCallerId) - callerId = callInfo.from(); - - if(callerId == null){ - Attribute attribute = verb.attribute("callerId"); - if (attribute != null) { - callerId = attribute.value(); - if (callerId != null && !callerId.isEmpty()) { - callerId = e164(callerId); - if (callerId == null) { - callerId = verb.attribute("callerId").value(); - final NotificationsDao notifications = storage.getNotificationsDao(); - final Notification notification = notification(ERROR_NOTIFICATION, 13214, callerId - + " is an invalid callerId."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return null; - } - } - } - } - return callerId; - } - - protected Tag conference(final Tag container) { - final List children = container.children(); - for (final Tag child : children) { - if (Nouns.conference.equals(child.name())) { - return child; - } - } - return null; - } - - protected int timeout(final Tag container) { - int timeout = 30; - Attribute attribute = container.attribute("timeout"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - timeout = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final NotificationsDao notifications = storage.getNotificationsDao(); - final Notification notification = notification(WARNING_NOTIFICATION, 13212, value - + " is not a valid timeout value for "); - notifications.addNotification(notification); - } - } - } - return timeout; - } - - protected int timeLimit(final Tag container) { - int timeLimit = 14400; - Attribute attribute = container.attribute("timeLimit"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - timeLimit = Integer.parseInt(value); - } catch (final NumberFormatException exception) { - final NotificationsDao notifications = storage.getNotificationsDao(); - final Notification notification = notification(WARNING_NOTIFICATION, 13216, value - + " is not a valid timeLimit value for "); - notifications.addNotification(notification); - } - } - } - return timeLimit; - } - } - - private final class StartDialing extends AbstractDialAction { - public StartDialing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (Tag.class.equals(klass)) { - verb = (Tag) message; - } - final String text = verb.text(); - if (text != null && !text.isEmpty()) { - //Build the appropriate tag for the text, such as Number, Client or SIP - final Tag.Builder builder = Tag.builder(); - // Read the next tag. - if(text.contains("@")) { - builder.setName(Nouns.SIP); - } else if (text.startsWith("client")) { - builder.setName(Nouns.client); - } else { - builder.setName(Nouns.number); - } - builder.setText(text); - Tag numberTag = builder.build(); - - //Change the Dial verb to include the Tag we created before - Tag.Builder tagBuilder = Tag.builder(); - tagBuilder.addChild(numberTag); - tagBuilder.setIterable(verb.isIterable()); - tagBuilder.setName(verb.name()); - tagBuilder.setParent(verb.parent()); - for (Attribute attribute : verb.attributes()) { - if(attribute != null) - tagBuilder.addAttribute(attribute); - } - verb = null; - verb = tagBuilder.build(); - } - - if (verb.hasChildren()) { - // Handle conferencing. - final Tag child = conference(verb); - if (child != null) { - final String name = child.text(); - final StringBuilder buffer = new StringBuilder(); - buffer.append(accountId.toString()).append(":").append(name); - final CreateConference create = new CreateConference(buffer.toString()); - conferenceManager.tell(create, source); - } else { - // Handle forking. - dialBranches = new ArrayList(); - dialChildren = new ArrayList(verb.children()); - dialChildrenWithAttributes = new HashMap(); - isForking = true; - final StartForking start = StartForking.instance(); - source.tell(start, source); - } - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - } - - private final class ProcessingDialChildren extends AbstractDialAction { - public ProcessingDialChildren(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - Class klass = message.getClass(); - if (CallManagerResponse.class.equals(klass)) { - final CallManagerResponse response = (CallManagerResponse) message; - final ActorRef branch = response.get(); - dialBranches.add(branch); - Tag child = dialChildren.get(0); - if (child.hasAttributes()) { - dialChildrenWithAttributes.put(branch, child); - } - dialChildren.remove(child); - } - if (!dialChildren.isEmpty()) { - CreateCall create = null; - final Tag child = dialChildren.get(0); - if (Nouns.client.equals(child.name())) { - create = new CreateCall(e164(callerId(verb)), e164(child.text()), null, null, false, timeout(verb), - CreateCall.Type.CLIENT, accountId); - } else if (Nouns.number.equals(child.name())) { - create = new CreateCall(e164(callerId(verb)), e164(child.text()), null, null, false, timeout(verb), - CreateCall.Type.PSTN, accountId); - } else if (Nouns.uri.equals(child.name())) { - create = new CreateCall(e164(callerId(verb)), e164(child.text()), null, null, false, timeout(verb), - CreateCall.Type.SIP, accountId); - } else if (Nouns.SIP.equals(child.name())) { - // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out - String username = null; - String password = null; - if (child.attribute("username") != null) { - username = child.attribute("username").value(); - } - if (child.attribute("password") != null) { - password = child.attribute("password").value(); - } - create = new CreateCall(e164(callerId(verb)), e164(child.text()), username, password, false, timeout(verb), - CreateCall.Type.SIP, accountId); - } - callManager.tell(create, source); - } else { - // Fork. - final Fork fork = Fork.instance(); - source.tell(fork, source); - dialChildren = null; - } - } - } - - private final class Forking extends AbstractDialAction { - public Forking(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallManagerResponse.class.equals(klass)) { - final CallManagerResponse response = (CallManagerResponse) message; - outboundCall = response.get(); - outboundCall.tell(new Observe(source), source); - outboundCall.tell(new Dial(), source); - } else if (Fork.class.equals(klass)) { - final Observe observe = new Observe(source); - final Dial dial = new Dial(); - for (final ActorRef branch : dialBranches) { - branch.tell(observe, source); - branch.tell(dial, source); - } - } - String path = configuration.subset("runtime-settings").getString("prompts-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - path += "ringing.wav"; - URI uri = null; - try { - uri = URI.create(path); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final Play play = new Play(uri, Short.MAX_VALUE); - callMediaGroup.tell(play, source); - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.create(timeout(verb), TimeUnit.SECONDS)); - } - } - - private final class AcquiringOutboundCallInfo extends AbstractDialAction { - public AcquiringOutboundCallInfo(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - if (isForking) { - dialBranches.remove(outboundCall); - for (final ActorRef branch : dialBranches) { - branch.tell(new Cancel(), source); - callManager.tell(new DestroyCall(branch), source); - } - dialBranches = null; - } - outboundCall.tell(new GetCallInfo(), source); - } - } - - private final class JoiningCalls extends AbstractDialAction { - public JoiningCalls(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final CallResponse response = (CallResponse) message; - outboundCallInfo = response.get(); - - // Check for any Dial verbs with url attributes (call screening url) - logger.info("Checking for Dial verbs with url attributes for this outboundcall"); - Tag child = dialChildrenWithAttributes.get(outboundCall); - if (child != null && child.attribute("url") != null) { - - URI url = new URL(child.attribute("url").value()).toURI(); - String method = null; - if (child.hasAttribute("method")) { - method = child.attribute("method").value().toUpperCase(); - } else { - method = "POST"; - } - - final SubVoiceInterpreterBuilder builder = new SubVoiceInterpreterBuilder(getContext().system()); - builder.setConfiguration(configuration); - builder.setStorage(storage); - builder.setCallManager(self()); - builder.setSmsService(smsService); - builder.setAccount(accountId); - builder.setVersion(version); - builder.setUrl(url); - builder.setMethod(method); - final ActorRef interpreter = builder.build(); - StartInterpreter start = new StartInterpreter(outboundCall); - Timeout expires = new Timeout(Duration.create(6000, TimeUnit.SECONDS)); - Future future = (Future) ask(interpreter, start, expires); - Object object = Await.result(future, Duration.create(6000, TimeUnit.SECONDS)); - - if (!End.class.equals(object.getClass())) { - fsm.transition(message, hangingUp); - return; - } - - // Stop SubVoiceInterpreter - outboundCall.tell(new StopObserving(interpreter), null); - getContext().stop(interpreter); - - } - final AddParticipant add = new AddParticipant(outboundCall); - call.tell(add, source); - } - } - - private final class Bridged extends AbstractDialAction { - public Bridged(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final int timeLimit = timeLimit(verb); - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.create(timeLimit, TimeUnit.SECONDS)); - callMediaGroup.tell(new Stop(), source); - } - } - - private void recordCall() { - logger.info("Start recording of the call"); - Configuration runtimeSettings = configuration.subset("runtime-settings"); - recordingSid = Sid.generate(Sid.Type.RECORDING); - String path = runtimeSettings.getString("recordings-path"); - String httpRecordingUri = runtimeSettings.getString("recordings-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - if (!httpRecordingUri.endsWith("/")) { - httpRecordingUri += "/"; - } - path += recordingSid.toString() + ".wav"; - httpRecordingUri += recordingSid.toString() + ".wav"; - this.recordingUri = URI.create(path); - this.publicRecordingUri = URI.create(httpRecordingUri); - call.tell(new StartRecordingCall(accountId, runtimeSettings, storage, recordingSid, recordingUri), null); - } - - private void executeDialAction(final Object message, final ActorRef outboundCall) { - logger.info("Proceeding to execute Dial Action attribute"); - this.dialActionExecuted = true; - final List parameters = parameters(); - - Attribute attribute = verb.attribute("action"); - - if (call != null) { - try { - logger.info("Trying to get outboundCall Info"); - final Timeout expires = new Timeout(Duration.create(5, TimeUnit.SECONDS)); - Future future = (Future) ask(call, new GetCallInfo(), expires); - CallResponse callResponse = (CallResponse) Await.result(future, - Duration.create(10, TimeUnit.SECONDS)); - callInfo = callResponse.get(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (outboundCall != null) { - try { - logger.info("Trying to get outboundCall Info"); - final Timeout expires = new Timeout(Duration.create(5, TimeUnit.SECONDS)); - Future future = (Future) ask(outboundCall, new GetCallInfo(), expires); - CallResponse callResponse = (CallResponse) Await.result(future, - Duration.create(10, TimeUnit.SECONDS)); - outboundCallInfo = callResponse.get(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Handle Failed Calls - if (message instanceof CallManagerResponse && !(((CallManagerResponse) message).succeeded())) { - parameters.add(new BasicNameValuePair("DialCallSid", null)); - parameters.add(new BasicNameValuePair("DialCallStatus", CallStateChanged.State.FAILED.name())); - parameters.add(new BasicNameValuePair("DialCallDuration", "0")); - parameters.add(new BasicNameValuePair("RecordingUrl", null)); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", null)); - } - // Handle No-Answer calls - else if (message instanceof ReceiveTimeout) { - if (outboundCallInfo != null) { - final String dialCallSid = this.outboundCallInfo.sid().toString(); - final CallStateChanged.State dialCallStatus = this.outboundCallInfo.state(); - final long dialCallDuration = new Interval(this.outboundCallInfo.dateCreated(), DateTime.now()).toDuration() - .getStandardSeconds(); - final String recordingUrl = this.recordingUri == null ? null : this.recordingUri.toString(); - final String publicRecordingUrl = this.publicRecordingUri == null ? null : this.publicRecordingUri.toString(); - - parameters.add(new BasicNameValuePair("DialCallSid", dialCallSid)); - // parameters.add(new BasicNameValuePair("DialCallStatus", dialCallStatus == null ? null : dialCallStatus - // .toString())); - parameters.add(new BasicNameValuePair("DialCallStatus", CallStateChanged.State.NO_ANSWER.name())); - parameters.add(new BasicNameValuePair("DialCallDuration", String.valueOf(dialCallDuration))); - parameters.add(new BasicNameValuePair("RecordingUrl", recordingUrl)); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", publicRecordingUrl)); - } else { - parameters.add(new BasicNameValuePair("DialCallSid", null)); - parameters.add(new BasicNameValuePair("DialCallStatus", CallStateChanged.State.NO_ANSWER.name())); - parameters.add(new BasicNameValuePair("DialCallDuration", "0")); - parameters.add(new BasicNameValuePair("RecordingUrl", null)); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", null)); - } - } - // Handle the rest of the cases - else { - if (outboundCallInfo != null) { - final String dialCallSid = this.outboundCallInfo.sid().toString(); - final CallStateChanged.State dialCallStatus = this.outboundCallInfo.state(); - final long dialCallDuration = new Interval(this.outboundCallInfo.dateCreated(), DateTime.now()).toDuration() - .getStandardSeconds(); - final String recordingUrl = this.recordingUri == null ? null : this.recordingUri.toString(); - final String publicRecordingUrl = this.publicRecordingUri == null ? null : this.publicRecordingUri.toString(); - - parameters.add(new BasicNameValuePair("DialCallSid", dialCallSid)); - //If Caller sent the BYE request, at the time we execute this method, the outbound call status is still in progress - if (callInfo.state().equals(CallStateChanged.State.COMPLETED)) { - parameters.add(new BasicNameValuePair("DialCallStatus", callInfo.state().toString())); - } else { - parameters.add(new BasicNameValuePair("DialCallStatus", dialCallStatus == null ? null : dialCallStatus - .toString())); - } - parameters.add(new BasicNameValuePair("DialCallDuration", String.valueOf(dialCallDuration))); - parameters.add(new BasicNameValuePair("RecordingUrl", recordingUrl)); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", publicRecordingUrl)); - } else { - parameters.add(new BasicNameValuePair("DialCallSid", null)); - parameters.add(new BasicNameValuePair("DialCallStatus", null)); - parameters.add(new BasicNameValuePair("DialCallDuration", "0")); - parameters.add(new BasicNameValuePair("RecordingUrl", null)); - parameters.add(new BasicNameValuePair("PublicRecordingUrl", null)); - } - } - - final NotificationsDao notifications = storage.getNotificationsDao(); - if (attribute != null) { - logger.info("Executing Dial Action attribute."); - String action = attribute.value(); - if (action != null && !action.isEmpty()) { - URI target = null; - try { - target = URI.create(action); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, action + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - self().tell(stop, self()); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Parse "method". - String method = "POST"; - attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13210, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - logger.info("Dial Action URL: "+uri.toString()+" Method: "+method); - logger.debug("Dial Action parameters: \n"+parameters); - // Redirect to the action url. - request = new HttpRequestDescriptor(uri, method, parameters); - // Tell the downloader to send the Dial Parameters to the Action url but we don't need a reply back so sender == - // null - downloader.tell(request, self()); - return; - } - - } - } - - private final class FinishDialing extends AbstractDialAction { - public FinishDialing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final State state = fsm.state(); - - if (message instanceof ReceiveTimeout) { - if (forking.equals(state)) { - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.Undefined()); - for (final ActorRef branch : dialBranches) { - executeDialAction(message, branch); - branch.tell(new Cancel(), source); - callManager.tell(new DestroyCall(branch), source); - } - dialBranches = null; - return; - } else if (bridged.equals(state)) { - outboundCall.tell(new Hangup(), source); - } - } - - if(sender == call){ - if(outboundCall != null) - outboundCall.tell(new Hangup(), self()); - } else { - call.tell(new Hangup(), self()); - } - - Attribute attribute = verb.attribute("action"); - if (attribute != null) { - logger.info("Executing Dial Action url"); - if (outboundCall != null) { - executeDialAction(message, outboundCall); - } else { - logger.info("Executing Dial Action url"); - executeDialAction(message, null); - } - return; - } else { - logger.info("Action attribute is null."); - } - - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - dialChildren = null; - outboundCall = null; - } - } - - private final class AcquiringConferenceInfo extends AbstractDialAction { - public AcquiringConferenceInfo(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final ConferenceCenterResponse response = (ConferenceCenterResponse) message; - conference = response.get(); - final GetConferenceInfo request = new GetConferenceInfo(); - conference.tell(new Observe(source), source); - conference.tell(request, source); - } - } - - private final class AcquiringConferenceMediaGroup extends AbstractDialAction { - public AcquiringConferenceMediaGroup(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final ConferenceResponse response = (ConferenceResponse) message; - conferenceInfo = response.get(); - conferenceState = conferenceInfo.state(); - final Tag child = conference(verb); - // If there is room join the conference. - int max = 40; - Attribute attribute = child.attribute("maxParticipants"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - max = Integer.parseInt(value); - } catch (final NumberFormatException ignored) { - } - } - } - if (conferenceInfo.participants().size() < max) { - final CreateMediaGroup request = new CreateMediaGroup(); - conference.tell(request, source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - } - - private final class InitializingConferenceMediaGroup extends AbstractDialAction { - public InitializingConferenceMediaGroup(final ActorRef source) { - super(source); - } - - @SuppressWarnings("unchecked") - @Override - public void execute(final Object message) throws Exception { - final ConferenceResponse response = (ConferenceResponse) message; - conferenceMediaGroup = response.get(); - conferenceMediaGroup.tell(new Observe(source), source); - final StartMediaGroup request = new StartMediaGroup(); - conferenceMediaGroup.tell(request, source); - } - } - - private final class JoiningConference extends AbstractDialAction { - public JoiningConference(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Tag child = conference(verb); - // Play beep. - boolean beep = true; - Attribute attribute = child.attribute("beep"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - beep = Boolean.parseBoolean(value); - } - } - if (beep) { - String path = configuration.subset("runtime-settings").getString("prompts-uri"); - if (!path.endsWith("/")) { - path += "/"; - } - path += "beep.wav"; - URI uri = null; - try { - uri = URI.create(path); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); - final NotificationsDao notifications = storage.getNotificationsDao(); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final Play play = new Play(uri, 1); - conferenceMediaGroup.tell(play, source); - } - // Join the conference. - final AddParticipant request = new AddParticipant(call); - conference.tell(request, source); - } - } - - private final class Conferencing extends AbstractDialAction { - public Conferencing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final NotificationsDao notifications = storage.getNotificationsDao(); - final Tag child = conference(verb); - // Mute - - Attribute attribute = child.attribute("muted"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - callMuted = Boolean.parseBoolean(value); - } - } - - if (callMuted) { - final Mute mute = new Mute(); - call.tell(mute, source); - } - // Parse start conference. - - attribute = child.attribute("startConferenceOnEnter"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - startConferenceOnEnter = Boolean.parseBoolean(value); - } - } - - if (!startConferenceOnEnter && conferenceState == ConferenceStateChanged.State.RUNNING_MODERATOR_ABSENT) { - - if (!callMuted) { - final Mute mute = new Mute(); - logger.info("Muting the call as startConferenceOnEnter =" + startConferenceOnEnter + " callMuted = " - + callMuted); - call.tell(mute, source); - } - - // Parse wait url. - URI waitUrl = new URL( - "http://127.0.0.1:8080/restcomm/music/rock/nickleus_-_original_guitar_song_200907251723.wav").toURI(); - attribute = child.attribute("waitUrl"); - if (attribute != null) { - String value = attribute.value(); - if (value != null && !value.isEmpty()) { - try { - waitUrl = URI.create(value); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 13233, method - + " is not a valid waitUrl value for "); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - - // TODO shouldn't we return here? - } - } - } - - final URI base = request.getUri(); - waitUrl = UriUtils.resolve(base, waitUrl); - // Parse method. - String method = "POST"; - attribute = child.attribute("waitMethod"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13234, method - + " is not a valid waitMethod value for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - // Start the waitUrl media player. - - if (waitUrl != null) { - final ConfVoiceInterpreterBuilder confVoiceInterpreterBuilder = new ConfVoiceInterpreterBuilder( - getContext().system()); - confVoiceInterpreterBuilder.setAccount(accountId); - confVoiceInterpreterBuilder.setCallInfo(callInfo); - confVoiceInterpreterBuilder.setConference(conference); - confVoiceInterpreterBuilder.setConfiguration(configuration); - confVoiceInterpreterBuilder.setEmailAddress(emailAddress); - confVoiceInterpreterBuilder.setMethod(method); - confVoiceInterpreterBuilder.setStorage(storage); - confVoiceInterpreterBuilder.setUrl(waitUrl); - confVoiceInterpreterBuilder.setVersion(version); - - confInterpreter = confVoiceInterpreterBuilder.build(); - - CreateWaitUrlConfMediaGroup createWaitUrlConfMediaGroup = new CreateWaitUrlConfMediaGroup(confInterpreter); - conference.tell(createWaitUrlConfMediaGroup, source); - } - - } else if (conferenceState == ConferenceStateChanged.State.RUNNING_MODERATOR_ABSENT) { - conference.tell(new ConferenceModeratorPresent(), source); - } - // Set timer. - final int timeLimit = timeLimit(verb); - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.create(timeLimit, TimeUnit.SECONDS)); - } - } - - private final class FinishConferencing extends AbstractDialAction { - public FinishConferencing(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - if (message instanceof ReceiveTimeout) { - final UntypedActorContext context = getContext(); - context.setReceiveTimeout(Duration.Undefined()); - final RemoveParticipant remove = new RemoveParticipant(call); - conference.tell(remove, source); - } - // Clean up.\ - callMediaGroup.tell(new StopMediaGroup(), source); - final DestroyMediaGroup destroy = new DestroyMediaGroup(conferenceMediaGroup); - conference.tell(destroy, source); - conferenceMediaGroup = null; - conference = null; - // Parse remaining conference attributes. - final NotificationsDao notifications = storage.getNotificationsDao(); - final Tag child = conference(verb); - // Parse "endConferenceOnExit" - boolean endOnExit = false; - Attribute attribute = child.attribute("endConferenceOnExit"); - if (attribute != null) { - final String value = attribute.value(); - if (value != null && !value.isEmpty()) { - endOnExit = Boolean.parseBoolean(value); - } - } - if (endOnExit) { - final StopConference stop = new StopConference(); - conference.tell(stop, source); - } - // Parse "action". - attribute = verb.attribute("action"); - if (attribute != null) { - String action = attribute.value(); - if (action != null && !action.isEmpty()) { - URI target = null; - try { - target = URI.create(action); - } catch (final Exception exception) { - final Notification notification = notification(ERROR_NOTIFICATION, 11100, action - + " is an invalid URI."); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); - source.tell(stop, source); - return; - } - final URI base = request.getUri(); - final URI uri = UriUtils.resolve(base, target); - // Parse "method". - String method = "POST"; - attribute = verb.attribute("method"); - if (attribute != null) { - method = attribute.value(); - if (method != null && !method.isEmpty()) { - if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { - final Notification notification = notification(WARNING_NOTIFICATION, 13210, method - + " is not a valid HTTP method for "); - notifications.addNotification(notification); - method = "POST"; - } - } else { - method = "POST"; - } - } - // Redirect to the action url. - final List parameters = parameters(); - request = new HttpRequestDescriptor(uri, method, parameters); - downloader.tell(request, source); - return; - } - } - // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); - parser.tell(next, source); - } - } - - private final class Finished extends AbstractAction { - public Finished(final ActorRef source) { - super(source); - } - - @Override - public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - if (CallStateChanged.class.equals(klass)) { - final CallStateChanged event = (CallStateChanged) message; - callState = event.state(); - if (callRecord != null) { - callRecord = callRecord.setStatus(callState.toString()); - final DateTime end = DateTime.now(); - callRecord = callRecord.setEndTime(end); - final int seconds = (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000; - callRecord = callRecord.setDuration(seconds); - final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); - records.updateCallDetailRecord(callRecord); - } - callback(); - } - // Cleanup the outbound call if necessary. - final State state = fsm.state(); - if (bridged.equals(state)) { - if (outboundCall != null) { - outboundCall.tell(new StopObserving(source), source); - outboundCall.tell(new Hangup(), source); - } - } - // If we still have a conference media group release it. - final StopMediaGroup stop = new StopMediaGroup(); - if (conferenceMediaGroup != null) { - conferenceMediaGroup.tell(stop, source); - final DestroyMediaGroup destroy = new DestroyMediaGroup(conferenceMediaGroup); - conference.tell(destroy, source); - conferenceMediaGroup = null; - } - // If the call is in a conference remove it. - if (conference != null) { - final RemoveParticipant remove = new RemoveParticipant(call); - conference.tell(remove, source); - } - // Destroy the media group(s). - if (callMediaGroup != null) { - callMediaGroup.tell(stop, source); - final DestroyMediaGroup destroy = new DestroyMediaGroup(callMediaGroup); - call.tell(destroy, source); - callMediaGroup = null; - } - // Destroy the Call(s). - callManager.tell(new DestroyCall(call), source); - if (outboundCall != null) - callManager.tell(new DestroyCall(outboundCall), source); - // Stop the dependencies. - final UntypedActorContext context = getContext(); - context.stop(mailer); - context.stop(downloader); - context.stop(asrService); - context.stop(faxService); - context.stop(cache); - context.stop(synthesizer); - // Stop the interpreter. - postCleanup(); - } - } - - @Override - public void postStop() { - if (fsm.state().equals(bridged) && outboundCall != null) { - outboundCall.tell(new Hangup(), null); - } - - // Issue https://bitbucket.org/telestax/telscale-restcomm/issue/247/ - final StopMediaGroup stop = new StopMediaGroup(); - if (confInterpreter != null) { - confInterpreter.tell(StopInterpreter.instance(), null); - getContext().stop(confInterpreter); - confInterpreter = null; - - final RemoveParticipant remove = new RemoveParticipant(call); - conference.tell(remove, null); - conference.tell(new StopObserving(self()), null); - - if(conferenceMediaGroup != null && !conferenceMediaGroup.isTerminated()) { - conferenceMediaGroup.tell(stop, null); - final DestroyMediaGroup destroy = new DestroyMediaGroup(conferenceMediaGroup); - conference.tell(destroy, null); - getContext().stop(conferenceMediaGroup); - conferenceMediaGroup = null; - } - - getContext().stop(conference); - } - - // Destroy the media group(s). - if (callMediaGroup != null) { - callMediaGroup.tell(stop, null); - final DestroyMediaGroup destroy = new DestroyMediaGroup(callMediaGroup); - call.tell(destroy, null); - getContext().stop(callMediaGroup); - callMediaGroup = null; - } - - postCleanup(); - super.postStop(); - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreterBuilder.java deleted file mode 100644 index 5a5ca0f68d..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/VoiceInterpreterBuilder.java +++ /dev/null @@ -1,135 +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.mobicents.servlet.restcomm.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; - -import java.net.URI; - -import org.apache.commons.configuration.Configuration; - -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.entities.Sid; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class VoiceInterpreterBuilder { - 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; - - /** - * @author thomas.quintana@telestax.com (Thomas Quintana) - */ - public VoiceInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - return system.actorOf(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, emailAddress, calls, conferences, sms, storage); - } - })); - } - - 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; - } -} \ No newline at end of file diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/End.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/End.java deleted file mode 100644 index 2a97126b8e..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/End.java +++ /dev/null @@ -1,40 +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.mobicents.servlet.restcomm.interpreter.rcml; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class End { - private static final class Singleton { - private static final End instance = new End(); - } - - private End() { - super(); - } - - public static End instance() { - return Singleton.instance; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/GetNextVerb.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/GetNextVerb.java deleted file mode 100644 index 32cc6e6598..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/GetNextVerb.java +++ /dev/null @@ -1,40 +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.mobicents.servlet.restcomm.interpreter.rcml; - -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -@Immutable -public final class GetNextVerb { - private static final class Singleton { - private static final GetNextVerb instance = new GetNextVerb(); - } - - private GetNextVerb() { - super(); - } - - public static GetNextVerb instance() { - return Singleton.instance; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/Parser.java b/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/Parser.java deleted file mode 100644 index 5d091e48e6..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/rcml/Parser.java +++ /dev/null @@ -1,173 +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.mobicents.servlet.restcomm.interpreter.rcml; - -import akka.actor.ActorRef; -import akka.actor.UntypedActor; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.util.Iterator; -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; - -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.*; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class Parser extends UntypedActor { - private final Tag document; - private final Iterator iterator; - - private Tag current; - - public Parser(final InputStream input) throws IOException { - this(new InputStreamReader(input)); - } - - public Parser(final Reader reader) throws IOException { - super(); - final XMLInputFactory inputs = XMLInputFactory.newInstance(); - inputs.setProperty("javax.xml.stream.isCoalescing", true); - XMLStreamReader stream = null; - try { - stream = inputs.createXMLStreamReader(reader); - document = parse(stream); - if (document == null) { - throw new IOException("There was an error parsing the RCML."); - } - iterator = document.iterator(); - } catch (final XMLStreamException exception) { - throw new IOException(exception); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (final XMLStreamException nested) { - throw new IOException(nested); - } - } - } - } - - public Parser(final String text) throws IOException { - this(new StringReader(text.trim().replaceAll("&([^;]+(?!(?:\\w|;)))", "&$1"))); - } - - private void end(final Stack builders, final XMLStreamReader stream) { - if (builders.size() > 1) { - final Tag.Builder builder = builders.pop(); - final Tag tag = builder.build(); - builders.peek().addChild(tag); - } - } - - private void start(final Stack builders, final XMLStreamReader stream) { - final Tag.Builder builder = Tag.builder(); - // Read the next tag. - builder.setName(stream.getLocalName()); - // Read the attributes. - final int limit = stream.getAttributeCount(); - for (int index = 0; index < limit; index++) { - final String name = stream.getAttributeLocalName(index); - final String value = stream.getAttributeValue(index).trim(); - final Attribute attribute = new Attribute(name, value); - builder.addAttribute(attribute); - } - builders.push(builder); - } - - private Tag next() { - while (iterator.hasNext()) { - final Tag tag = iterator.next(); - if (isVerb(tag)) { - if (current != null && current.hasChildren()) { - final List children = current.children(); - if (children.contains(tag)) { - continue; - } - } - current = tag; - return current; - } - } - return null; - } - - private Tag parse(final XMLStreamReader stream) throws IOException, XMLStreamException { - final Stack builders = new Stack(); - while (stream.hasNext()) { - switch (stream.next()) { - case START_ELEMENT: { - start(builders, stream); - continue; - } - case CHARACTERS: { - text(builders, stream); - continue; - } - case END_ELEMENT: { - end(builders, stream); - continue; - } - case END_DOCUMENT: { - if (!builders.isEmpty()) { - return builders.pop().build(); - } - } - } - } - return null; - } - - @Override - public void onReceive(final Object message) throws Exception { - final Class klass = message.getClass(); - final ActorRef self = self(); - final ActorRef sender = sender(); - if (GetNextVerb.class.equals(klass)) { - final Tag verb = next(); - if (verb != null) { - sender.tell(verb, self); - } else { - final End end = End.instance(); - sender.tell(end, sender); - } - } - } - - private void text(final Stack builders, final XMLStreamReader stream) { - if (!stream.isWhiteSpace()) { - // Read the text. - final Tag.Builder builder = builders.peek(); - final String text = stream.getText().trim(); - builder.setText(text); - } - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/AudioPlayerInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java similarity index 84% rename from restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/AudioPlayerInterpreter.java rename to restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java index f84aed5292..14284931f5 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/AudioPlayerInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java @@ -17,14 +17,14 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.interpreter; +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 new file mode 100644 index 0000000000..1846d5ae7c --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -0,0 +1,2317 @@ +/* + * 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.Actor; +import akka.actor.ActorRef; +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 akka.util.Timeout; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.StringUtils; +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.joda.time.DateTime; +import org.restcomm.connect.asr.AsrInfo; +import org.restcomm.connect.asr.AsrRequest; +import org.restcomm.connect.asr.AsrResponse; +import org.restcomm.connect.asr.GetAsrInfo; +import org.restcomm.connect.asr.ISpeechAsr; +import org.restcomm.connect.commons.cache.DiskCacheFactory; +import org.restcomm.connect.commons.cache.DiskCacheRequest; +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.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; +import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.util.UriUtils; +import org.restcomm.connect.commons.util.WavUtils; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.RecordingsDao; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.dao.TranscriptionsDao; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.MediaAttributes; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.dao.entities.Recording; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessage.Direction; +import org.restcomm.connect.dao.entities.SmsMessage.Status; +import org.restcomm.connect.dao.entities.Transcription; +import org.restcomm.connect.email.EmailService; +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.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionFeatureAccessRequest; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.fax.FaxRequest; +import org.restcomm.connect.fax.InterfaxService; +import org.restcomm.connect.http.client.Downloader; +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.rcml.Attribute; +import org.restcomm.connect.interpreter.rcml.GetNextVerb; +import org.restcomm.connect.interpreter.rcml.Parser; +import org.restcomm.connect.interpreter.rcml.ParserFailed; +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.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; +import org.restcomm.connect.sms.api.CreateSmsSession; +import org.restcomm.connect.sms.api.DestroySmsSession; +import org.restcomm.connect.sms.api.SmsServiceResponse; +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.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallManagerResponse; +import org.restcomm.connect.telephony.api.CallStateChanged; +import org.restcomm.connect.telephony.api.FeatureAccessRequest; +import org.restcomm.connect.telephony.api.GetCallInfo; +import org.restcomm.connect.telephony.api.Hangup; +import org.restcomm.connect.telephony.api.Reject; +import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; +import org.restcomm.connect.tts.api.SpeechSynthesizerInfo; +import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; +import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.servlet.sip.SipServletResponse; +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +import static akka.pattern.Patterns.ask; + +/** + * @author thomas.quintana@telestax.com (Thomas Quintana) + * @author jean.deruelle@telestax.com + * @author gvagenas@telestax.com + * @author pavel.slegr@telestax.com + */ +public abstract class BaseVoiceInterpreter extends RestcommUntypedActor { + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + static final int ERROR_NOTIFICATION = 0; + static final int WARNING_NOTIFICATION = 1; + static final Pattern PATTERN = Pattern.compile("[\\*#0-9]{1,12}"); + static String EMAIL_SENDER = "restcomm@restcomm.org"; + + // States for the FSM. + // ========================== + final State uninitialized; + final State acquiringAsrInfo; + final State acquiringSynthesizerInfo; + final State acquiringCallInfo; + final State playingRejectionPrompt; + final State pausing; + final State caching; + final State checkingCache; + final State playing; + final State synthesizing; + final State redirecting; + final State faxing; + final State processingGatherChildren; + final State gathering; + final State finishGathering; + final State creatingRecording; + final State finishRecording; + final State creatingSmsSession; + final State sendingSms; + final State hangingUp; + final State sendingEmail; + final State continuousGathering; + // final State finished; + + // FSM. + FiniteStateMachine fsm = null; + // The user specific configuration. + Configuration configuration = null; + // The block storage cache. + private ActorRef cache; + String cachePath = null; + // The downloader will fetch resources for us using HTTP. + ActorRef downloader = null; + // The mail man that will deliver e-mail. + ActorRef mailerNotify = null; + ActorRef mailerService = null; + // The call manager. + ActorRef callManager = null; + // The conference manager. + ActorRef conferenceManager = null; + // The automatic speech recognition service. + private ActorRef asrService; + int outstandingAsrRequests; + // The fax service. + private ActorRef faxService; + // The SMS service = null. + ActorRef smsService = null; + Map smsSessions = null; + // The storage engine. + DaoManager storage = null; + // The text to speech synthesizer service. + private ActorRef synthesizer; + // The languages supported by the automatic speech recognition service. + AsrInfo asrInfo = null; + // The languages supported by the text to speech synthesizer service. + SpeechSynthesizerInfo synthesizerInfo = null; + // The call being handled by this interpreter. + ActorRef call = null; + // The information for this call. + CallInfo callInfo = null; + // The call state. + CallStateChanged.State callState = null; + // The last outbound call response. + Integer outboundCallResponse = null; + // A call detail record. + CallDetailRecord callRecord = null; + + // State for outbound calls. + ActorRef outboundCall = null; + CallInfo outboundCallInfo = null; + + // State for the gather verb. + List gatherChildren = null; + List gatherPrompts = null; + // The call recording stuff. + Sid recordingSid = null; + URI recordingUri = null; + URI publicRecordingUri = null; + MediaAttributes.MediaType recordingMediaType = null; + // Information to reach the application that will be executed + // by this interpreter. + Sid accountId; + Sid phoneId; + String version; + URI url; + String method; + URI fallbackUrl; + String fallbackMethod; + URI referUrl; + String referMethod; + String referTarget; + String transferor; + String transferee; + URI viStatusCallback; + String viStatusCallbackMethod; + String emailAddress; + // application data. + HttpRequestDescriptor request; + HttpRequestDescriptor requestCallback; + HttpResponseDescriptor response; + // The RCML parser. + ActorRef parser; + Tag verb; + Tag gatherVerb; + Boolean processingGather = false; + Boolean dtmfReceived = false; + String finishOnKey; + int numberOfDigits = Short.MAX_VALUE; + StringBuffer collectedDigits; + String speechResult; + //Monitoring service + ActorRef monitoring; + + final Set transitions = new HashSet(); + int recordingDuration = -1; + + protected RestcommConfiguration restcommConfiguration; + + //List of extensions for VoiceInterpreter + List extensions; + + public BaseVoiceInterpreter() { + super(); + restcommConfiguration = RestcommConfiguration.getInstance(); + final ActorRef source = self(); + // 20 States in common + uninitialized = new State("uninitialized", null, null); + acquiringAsrInfo = new State("acquiring asr info", new AcquiringAsrInfo(source), null); + acquiringSynthesizerInfo = new State("acquiring tts info", new AcquiringSpeechSynthesizerInfo(source), null); + acquiringCallInfo = new State("acquiring call info", new AcquiringCallInfo(source), null); + playingRejectionPrompt = new State("playing rejection prompt", new PlayingRejectionPrompt(source), null); + pausing = new State("pausing", new Pausing(source), null); + caching = new State("caching", new Caching(source), null); + checkingCache = new State("checkingCache", new CheckCache(source), null); + playing = new State("playing", new Playing(source), null); + synthesizing = new State("synthesizing", new Synthesizing(source), null); + redirecting = new State("redirecting", new Redirecting(source), null); + faxing = new State("faxing", new Faxing(source), null); + gathering = new State("gathering", new Gathering(source), null); + processingGatherChildren = new State("processing gather children", new ProcessingGatherChildren(source), null); + finishGathering = new State("finish gathering", new FinishGathering(source), null); + creatingRecording = new State("creating recording", new CreatingRecording(source), null); + finishRecording = new State("finish recording", new FinishRecording(source), null); + creatingSmsSession = new State("creating sms session", new CreatingSmsSession(source), null); + sendingSms = new State("sending sms", new SendingSms(source), null); + hangingUp = new State("hanging up", new HangingUp(source), null); + sendingEmail = new State("sending Email", new SendingEmail(source), null); + continuousGathering = new State("push partial result", new PartialGathering(source), null); + + // Initialize the transitions for the FSM. + transitions.add(new Transition(uninitialized, acquiringAsrInfo)); + transitions.add(new Transition(acquiringAsrInfo, acquiringSynthesizerInfo)); + transitions.add(new Transition(acquiringSynthesizerInfo, acquiringCallInfo)); + transitions.add(new Transition(pausing, hangingUp)); + transitions.add(new Transition(playingRejectionPrompt, hangingUp)); + transitions.add(new Transition(faxing, faxing)); + transitions.add(new Transition(faxing, caching)); + transitions.add(new Transition(faxing, pausing)); + transitions.add(new Transition(faxing, redirecting)); + transitions.add(new Transition(faxing, synthesizing)); + transitions.add(new Transition(faxing, processingGatherChildren)); + transitions.add(new Transition(faxing, creatingRecording)); + transitions.add(new Transition(faxing, creatingSmsSession)); + transitions.add(new Transition(faxing, hangingUp)); + transitions.add(new Transition(sendingEmail, sendingEmail)); + transitions.add(new Transition(sendingEmail, caching)); + transitions.add(new Transition(sendingEmail, pausing)); + transitions.add(new Transition(sendingEmail, redirecting)); + transitions.add(new Transition(sendingEmail, synthesizing)); + transitions.add(new Transition(sendingEmail, processingGatherChildren)); + transitions.add(new Transition(sendingEmail, creatingRecording)); + transitions.add(new Transition(sendingEmail, creatingSmsSession)); + transitions.add(new Transition(sendingEmail, hangingUp)); + transitions.add(new Transition(caching, faxing)); + transitions.add(new Transition(caching, sendingEmail)); + transitions.add(new Transition(caching, playing)); + transitions.add(new Transition(caching, caching)); + transitions.add(new Transition(caching, pausing)); + transitions.add(new Transition(caching, redirecting)); + transitions.add(new Transition(caching, synthesizing)); + transitions.add(new Transition(caching, processingGatherChildren)); + transitions.add(new Transition(caching, creatingRecording)); + transitions.add(new Transition(caching, creatingSmsSession)); + transitions.add(new Transition(caching, hangingUp)); + transitions.add(new Transition(checkingCache, synthesizing)); + transitions.add(new Transition(checkingCache, playing)); + transitions.add(new Transition(checkingCache, checkingCache)); + transitions.add(new Transition(playing, hangingUp)); + transitions.add(new Transition(synthesizing, faxing)); + transitions.add(new Transition(synthesizing, sendingEmail)); + transitions.add(new Transition(synthesizing, pausing)); + transitions.add(new Transition(synthesizing, checkingCache)); + transitions.add(new Transition(synthesizing, caching)); + transitions.add(new Transition(synthesizing, redirecting)); + transitions.add(new Transition(synthesizing, processingGatherChildren)); + transitions.add(new Transition(synthesizing, creatingRecording)); + transitions.add(new Transition(synthesizing, creatingSmsSession)); + transitions.add(new Transition(synthesizing, synthesizing)); + transitions.add(new Transition(synthesizing, hangingUp)); + transitions.add(new Transition(redirecting, faxing)); + transitions.add(new Transition(redirecting, sendingEmail)); + transitions.add(new Transition(redirecting, pausing)); + transitions.add(new Transition(redirecting, checkingCache)); + transitions.add(new Transition(redirecting, caching)); + transitions.add(new Transition(redirecting, synthesizing)); + transitions.add(new Transition(redirecting, redirecting)); + transitions.add(new Transition(redirecting, processingGatherChildren)); + transitions.add(new Transition(redirecting, creatingRecording)); + transitions.add(new Transition(redirecting, creatingSmsSession)); + transitions.add(new Transition(redirecting, hangingUp)); + transitions.add(new Transition(creatingRecording, finishRecording)); + transitions.add(new Transition(creatingRecording, hangingUp)); + transitions.add(new Transition(finishRecording, faxing)); + transitions.add(new Transition(finishRecording, sendingEmail)); + transitions.add(new Transition(finishRecording, pausing)); + transitions.add(new Transition(finishRecording, checkingCache)); + transitions.add(new Transition(finishRecording, caching)); + transitions.add(new Transition(finishRecording, synthesizing)); + transitions.add(new Transition(finishRecording, redirecting)); + transitions.add(new Transition(finishRecording, processingGatherChildren)); + transitions.add(new Transition(finishRecording, creatingRecording)); + transitions.add(new Transition(finishRecording, creatingSmsSession)); + transitions.add(new Transition(finishRecording, hangingUp)); + transitions.add(new Transition(processingGatherChildren, processingGatherChildren)); + transitions.add(new Transition(processingGatherChildren, gathering)); + transitions.add(new Transition(processingGatherChildren, synthesizing)); + transitions.add(new Transition(processingGatherChildren, hangingUp)); + + transitions.add(new Transition(gathering, finishGathering)); + transitions.add(new Transition(gathering, hangingUp)); + transitions.add(new Transition(gathering, continuousGathering)); + + transitions.add(new Transition(continuousGathering, continuousGathering)); + transitions.add(new Transition(continuousGathering, finishGathering)); + + transitions.add(new Transition(finishGathering, faxing)); + transitions.add(new Transition(finishGathering, sendingEmail)); + transitions.add(new Transition(finishGathering, pausing)); + transitions.add(new Transition(finishGathering, checkingCache)); + transitions.add(new Transition(finishGathering, caching)); + transitions.add(new Transition(finishGathering, synthesizing)); + transitions.add(new Transition(finishGathering, redirecting)); + transitions.add(new Transition(finishGathering, processingGatherChildren)); + transitions.add(new Transition(finishGathering, creatingRecording)); + transitions.add(new Transition(finishGathering, creatingSmsSession)); + transitions.add(new Transition(finishGathering, hangingUp)); + transitions.add(new Transition(creatingSmsSession, sendingSms)); + transitions.add(new Transition(creatingSmsSession, hangingUp)); + transitions.add(new Transition(sendingSms, faxing)); + transitions.add(new Transition(sendingSms, sendingEmail)); + transitions.add(new Transition(sendingSms, pausing)); + transitions.add(new Transition(sendingSms, caching)); + transitions.add(new Transition(sendingSms, synthesizing)); + transitions.add(new Transition(sendingSms, redirecting)); + transitions.add(new Transition(sendingSms, processingGatherChildren)); + transitions.add(new Transition(sendingSms, creatingRecording)); + transitions.add(new Transition(sendingSms, creatingSmsSession)); + transitions.add(new Transition(sendingSms, hangingUp)); + + extensions = ExtensionController.getInstance().getExtensions(ExtensionType.FeatureAccessControl); + } + + @Override + public abstract void onReceive(Object arg0) throws Exception; + + abstract List parameters(); + + protected URI resolve(URI uri){ + return UriUtils.resolve(uri); + } + + public ActorRef getAsrService() { + if (asrService == null || (asrService != null && asrService.isTerminated())) { + asrService = asr(configuration.subset("speech-recognizer")); + } + return asrService; + } + + private boolean checkAsrService() { + boolean AsrActive=false; + Configuration Asrconfiguration=configuration.subset("speech-recognizer"); + if (Asrconfiguration.getString("api-key") != null && !Asrconfiguration.getString("api-key").isEmpty()){ + AsrActive=true; + } + return AsrActive; + } + + ActorRef asr(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + @Override + public Actor create() throws Exception { + return new ISpeechAsr(configuration); + } + }); + return getContext().actorOf(props); + } + + @SuppressWarnings("unchecked") + void asrResponse(final Object message) { + final Class klass = message.getClass(); + if (AsrResponse.class.equals(klass)) { + final AsrResponse response = (AsrResponse) message; + Transcription transcription = (Transcription) response.attributes().get("transcription"); + if (response.succeeded()) { + transcription = transcription.setStatus(Transcription.Status.COMPLETED); + if (response.get() != null ) { + transcription = transcription.setTranscriptionText(response.get()); + } + } else { + transcription = transcription.setStatus(Transcription.Status.FAILED); + } + final TranscriptionsDao transcriptions = storage.getTranscriptionsDao(); + transcriptions.updateTranscription(transcription); + // Notify the callback listener. + final Object attribute = response.attributes().get("callback"); + if (attribute != null) { + final URI callback = (URI) attribute; + final List parameters = parameters(); + request = new HttpRequestDescriptor(callback, "POST", parameters); + downloader.tell(request, null); + } + // Update pending asr responses. + outstandingAsrRequests--; + // Try to stop the interpreter. + postCleanup(); + } + } + + public ActorRef getFaxService() { + if (faxService == null || (faxService != null && faxService.isTerminated())) { + faxService = fax(configuration.subset("fax-service")); + } + return faxService; + } + + ActorRef fax(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + @Override + public Actor create() throws Exception { + return new InterfaxService(configuration); + } + }); + return getContext().actorOf(props); + } + + LinkedList states = new LinkedList(Arrays.asList("queued", "ringing", "in-progress", "completed", "busy", "failed", "no-answer", "canceled")); + + //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 + //Downloader finish with this callback before shutdown everything. Issue https://github.com/Mobicents/RestComm/issues/437 + void callback(boolean ask) { + if (viStatusCallback != null) { + if (states.remove(callState.toString().toLowerCase())) { + if (logger.isInfoEnabled()) { + logger.info("About to execute viStatusCallback: " + viStatusCallback.toString()); + } + if (viStatusCallbackMethod == null) { + viStatusCallbackMethod = "POST"; + } + final List parameters = parameters(); + requestCallback = new HttpRequestDescriptor(viStatusCallback, viStatusCallbackMethod, parameters); + if (!ask) { + downloader.tell(requestCallback, null); + } else if (ask) { + final Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS)); + Future future = (Future) ask(downloader, requestCallback, timeout); + DownloaderResponse downloaderResponse = null; + try { + downloaderResponse = (DownloaderResponse) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + } catch (Exception e) { + logger.error("Exception during callback with ask pattern"); + } + } + } else { + if (logger.isInfoEnabled()) { + logger.info("Status Callback has been already executed for state: ",callState.toString()); + } + } + } else if(logger.isInfoEnabled()){ + logger.info("status callback is null"); + } + + } + + void callback() { + callback(false); + } + + public ActorRef getCache() { + if (cache == null || (cache != null && cache.isTerminated())) { + final Configuration runtime = configuration.subset("runtime-settings"); + String path = runtime.getString("cache-path"); + if (!path.endsWith("/")) { + path = path + "/"; + } + path = path + accountId.toString(); + cachePath = path; + String uri = runtime.getString("cache-uri"); + if (!uri.endsWith("/")) { + uri = uri + "/"; + } + try { + uri = UriUtils.resolve(new URI(uri)).toString(); + } catch (URISyntaxException e) { + logger.error("URISyntaxException while trying to resolve Cache URI: " + e); + } + uri = uri + accountId.toString(); + cache = cache(path, uri); + } + return cache; + } + + protected ActorRef cache(final String path, final String uri) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + @Override + public UntypedActor create() throws Exception { + return new DiskCacheFactory(configuration).getDiskCache(path, uri); + } + }); + return getContext().actorOf(props); + } + + protected ActorRef downloader() { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws Exception { + return new Downloader(); + } + }); + return getContext().actorOf(props); + } + + String e164(final String number) { + if (configuration.subset("runtime-settings").getBoolean("normalize-numbers-for-outbound-calls")) { + final PhoneNumberUtil numbersUtil = PhoneNumberUtil.getInstance(); + try { + final PhoneNumber result = numbersUtil.parse(number, "US"); + return numbersUtil.format(result, PhoneNumberFormat.E164); + } catch (final NumberParseException ignored) { + return number; + } + } else { + return number; + } + } + + void invalidVerb(final Tag verb) { + final ActorRef self = self(); + // Get the next verb. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self); + } + + ActorRef mailer(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public Actor create() throws Exception { + return new EmailService(configuration); + } + }); + return getContext().actorOf(props); + } + + 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); + builder.setSid(sid); + builder.setAccountSid(accountId); + builder.setCallSid(callInfo.sid()); + builder.setApiVersion(version); + builder.setLog(log); + builder.setErrorCode(error); + String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); + try { + base = UriUtils.resolve(new URI(base)).toString(); + } catch (URISyntaxException e) { + logger.error("URISyntaxException when trying to resolve Error-Dictionary URI: "+e); + } + StringBuilder buffer = new StringBuilder(); + buffer.append(base); + if (!base.endsWith("/")) { + buffer.append("/"); + } + buffer.append(error).append(".html"); + final URI info = URI.create(buffer.toString()); + builder.setMoreInfo(info); + builder.setMessageText(message); + final DateTime now = DateTime.now(); + builder.setMessageDate(now); + if (request != null) { + builder.setRequestUrl(request.getUri()); + builder.setRequestMethod(request.getMethod()); + builder.setRequestVariables(request.getParametersAsString()); + } + if (response != null) { + builder.setResponseHeaders(response.getHeadersAsString()); + final String type = response.getContentType(); + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + try { + builder.setResponseBody(response.getContentAsString()); + } catch (final IOException exception) { + logger.error( + "There was an error while reading the contents of the resource " + "located @ " + url.toString(), + exception); + } + } + } + buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/"); + buffer.append(accountId.toString()).append("/Notifications/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + return builder.build(); + } + + ActorRef parser(final String xml) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public UntypedActor create() throws IOException { + return new Parser(xml, self()); + } + }); + return getContext().actorOf(props); + } + + void postCleanup() { + if (smsSessions.isEmpty() && outstandingAsrRequests == 0) { + final UntypedActorContext context = getContext(); + if (parser != null) + getContext().stop(parser); + context.stop(self()); + } + if (downloader != null && !downloader.isTerminated()) { + getContext().stop(downloader); + } + } + + void sendMail(final Notification notification) { + if (emailAddress == null || emailAddress.isEmpty()) { + return; + } + final String EMAIL_SUBJECT = "RestComm Error Notification - Attention Required"; + final StringBuilder buffer = new StringBuilder(); + buffer.append("").append("Sid: ").append("
      "); + buffer.append(notification.getSid().toString()).append("
      "); + buffer.append("").append("Account Sid: ").append("
      "); + buffer.append(notification.getAccountSid().toString()).append("
      "); + buffer.append("").append("Call Sid: ").append("
      "); + buffer.append(notification.getCallSid().toString()).append("
      "); + buffer.append("").append("API Version: ").append("
      "); + buffer.append(notification.getApiVersion()).append("
      "); + buffer.append("").append("Log: ").append("
      "); + buffer.append(notification.getLog() == ERROR_NOTIFICATION ? "ERROR" : "WARNING").append("
      "); + buffer.append("").append("Error Code: ").append("
      "); + buffer.append(notification.getErrorCode()).append("
      "); + buffer.append("").append("More Information: ").append("
      "); + buffer.append(notification.getMoreInfo().toString()).append("
      "); + buffer.append("").append("Message Text: ").append("
      "); + buffer.append(notification.getMessageText()).append("
      "); + buffer.append("").append("Message Date: ").append("
      "); + buffer.append(notification.getMessageDate().toString()).append("
      "); + buffer.append("").append("Request URL: ").append("
      "); + buffer.append(notification.getRequestUrl().toString()).append("
      "); + buffer.append("").append("Request Method: ").append("
      "); + buffer.append(notification.getRequestMethod()).append("
      "); + buffer.append("").append("Request Variables: ").append("
      "); + buffer.append(notification.getRequestVariables()).append("
      "); + buffer.append("").append("Response Headers: ").append("
      "); + buffer.append(notification.getResponseHeaders()).append("
      "); + buffer.append("").append("Response Body: ").append("
      "); + buffer.append(notification.getResponseBody()).append("
      "); + final Mail emailMsg = new Mail(EMAIL_SENDER,emailAddress,EMAIL_SUBJECT, buffer.toString()); + if (mailerNotify == null){ + mailerNotify = mailer(configuration.subset("smtp-notify")); + } + mailerNotify.tell(new EmailRequest(emailMsg), self()); + } + + private final class SendingEmail extends AbstractAction { + public SendingEmail(final ActorRef source){ + super(source); + } + + @Override + public void execute( final Object message) throws Exception { + final Tag verb = (Tag)message; + // Parse "from". + String from; + Attribute attribute = verb.attribute("from"); + if (attribute != null) { + from = attribute.value(); + }else{ + Exception error = new Exception("From attribute was not defined"); + source.tell(new EmailResponse(error,error.getMessage()), source); + return; + } + + // Parse "to". + String to; + attribute = verb.attribute("to"); + if (attribute != null) { + to = attribute.value(); + }else{ + Exception error = new Exception("To attribute was not defined"); + source.tell(new EmailResponse(error,error.getMessage()), source); + return; + } + + // Parse "cc". + String cc=""; + attribute = verb.attribute("cc"); + if (attribute != null) { + cc = attribute.value(); + } + + // Parse "bcc". + String bcc=""; + attribute = verb.attribute("bcc"); + if (attribute != null) { + bcc = attribute.value(); + } + + // Parse "subject" + String subject; + attribute = verb.attribute("subject"); + if (attribute != null) { + subject = attribute.value(); + }else{ + subject="Restcomm Email Service"; + } + + // Send the email. + final Mail emailMsg = new Mail(from, to, subject, verb.text(),cc,bcc); + if (mailerService == null){ + mailerService = mailer(configuration.subset("smtp-service")); + } + mailerService.tell(new EmailRequest(emailMsg), self()); + } + } + + void smsResponse(final Object message) { + final Class klass = message.getClass(); + final ActorRef self = self(); + if (SmsSessionResponse.class.equals(klass)) { + final SmsSessionResponse response = (SmsSessionResponse) message; + final SmsSessionInfo info = response.info(); + SmsMessage record = (SmsMessage) info.attributes().get("record"); + final SmsMessagesDao messages = storage.getSmsMessagesDao(); + messages.updateSmsMessage(record); + // Notify the callback listener. + final Object attribute = info.attributes().get("callback"); + if (attribute != null) { + final URI callback = (URI) attribute; + final List parameters = parameters(); + request = new HttpRequestDescriptor(callback, "POST", parameters); + downloader.tell(request, null); + } + // Destroy the sms session. + final ActorRef session = smsSessions.remove(record.getSid()); + final DestroySmsSession destroy = new DestroySmsSession(session); + smsService.tell(destroy, self); + } + } + + public ActorRef getSynthesizer() { + if (synthesizer == null || (synthesizer != null && synthesizer.isTerminated())) { + String ttsEngine = configuration.subset("speech-synthesizer").getString("[@active]"); + Configuration ttsConf = configuration.subset(ttsEngine); + synthesizer = tts(ttsConf); + } + return synthesizer; + } + + ActorRef tts(final Configuration ttsConf) { + final String classpath = ttsConf.getString("[@class]"); + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public Actor create() throws Exception { + return (UntypedActor) Class.forName(classpath).getConstructor(Configuration.class).newInstance(ttsConf); + } + }); + return getContext().actorOf(props); + } + + protected boolean is(State state) { + return this.fsm.state().equals(state); + } + + abstract class AbstractAction implements Action { + protected final ActorRef source; + + public AbstractAction(final ActorRef source) { + super(); + this.source = source; + } + } + + final class AcquiringAsrInfo extends AbstractAction { + public AcquiringAsrInfo(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + getAsrService().tell(new GetAsrInfo(), source); + } + } + + final class AcquiringSpeechSynthesizerInfo extends AbstractAction { + public AcquiringSpeechSynthesizerInfo(final ActorRef source) { + super(source); + } + + @SuppressWarnings({ "unchecked" }) + @Override + public void execute(final Object message) throws Exception { + final AsrResponse response = (AsrResponse) message; + asrInfo = response.get(); + getSynthesizer().tell(new GetSpeechSynthesizerInfo(), source); + } + } + + final class AcquiringCallInfo extends AbstractAction { + public AcquiringCallInfo(final ActorRef source) { + super(source); + } + + @SuppressWarnings({ "unchecked" }) + @Override + public void execute(final Object message) throws Exception { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + synthesizerInfo = response.get(); +// call.tell(new Observe(source), source); +// //Enable Monitoring Service for the call +// if (monitoring != null) +// call.tell(new Observe(monitoring), source); + call.tell(new GetCallInfo(), source); + } + } + + final class NotFound extends AbstractAction { + public NotFound(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + // final Class klass = message.getClass(); + final DownloaderResponse response = (DownloaderResponse) message; + if (logger.isDebugEnabled()){ + logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); + } + final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " + + response.get().getURI()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + // Hang up the call. + call.tell(new org.restcomm.connect.telephony.api.NotFound(), source); + } + } + + final class Rejecting extends AbstractAction { + public Rejecting(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + String reason = "rejected"; + Attribute attribute = verb.attribute("reason"); + if (attribute != null) { + reason = attribute.value(); + if (reason != null && !reason.isEmpty()) { + if ("rejected".equalsIgnoreCase(reason)) { + reason = "rejected"; + } else if ("busy".equalsIgnoreCase(reason)) { + reason = "busy"; + } else { + reason = "rejected"; + } + } else { + reason = "rejected"; + } + } + // Reject the call. + call.tell(new Reject(reason), source); + } + } + + final class PlayingRejectionPrompt extends AbstractAction { + public PlayingRejectionPrompt(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + String path = configuration.subset("runtime-settings").getString("prompts-uri"); + if (!path.endsWith("/")) { + path += "/"; + } + path += "reject.wav"; + URI uri = null; + try { + uri = UriUtils.resolve(new URI(path)); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final Play play = new Play(uri, 1); + call.tell(play, source); + } + } + + final class Faxing extends AbstractAction { + public Faxing(final ActorRef source) { + super(source); + } + + @Override + public void execute(Object message) throws Exception { + final DiskCacheResponse response = (DiskCacheResponse) message; + // Parse "from". + String from = callInfo.to(); + Attribute attribute = verb.attribute("from"); + if (attribute != null) { + from = attribute.value(); + if (from != null && from.isEmpty()) { + from = e164(from); + if (from == null) { + from = verb.attribute("from").value(); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + } + // Parse "to". + String to = callInfo.from(); + attribute = verb.attribute("to"); + if (attribute != null) { + to = attribute.value(); + if (to != null && !to.isEmpty()) { + to = e164(to); + if (to == null) { + to = verb.attribute("to").value(); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + } + // Send the fax. + final String uri = response.get().toString(); + final int offset = uri.lastIndexOf("/"); + final String path = cachePath + "/" + uri.substring(offset + 1, uri.length()); + final FaxRequest fax = new FaxRequest(to, new File(path)); + getFaxService().tell(fax, source); + } + } + + final class Pausing extends AbstractAction { + public Pausing(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + int length = 1; + final Attribute attribute = verb.attribute("length"); + if (attribute != null) { + final String number = attribute.value(); + if (number != null && !number.isEmpty()) { + try { + length = Integer.parseInt(number); + } catch (final NumberFormatException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13910, "Invalid length value."); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + } + } + } + final UntypedActorContext context = getContext(); + context.setReceiveTimeout(Duration.create(length, TimeUnit.SECONDS)); + } + } + + final class CheckCache extends AbstractAction { + public CheckCache(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + // else { + // logger.info("Can't check cache, message not verb. Moving to the next verb"); + // // final GetNextVerb next = GetNextVerb.instance(); + // // parser.tell(next, source); + // return; + // } + String hash = hash(verb); + DiskCacheRequest request = new DiskCacheRequest(hash); + if (logger.isErrorEnabled()) { + logger.info("Checking cache for hash: " + hash); + } + getCache().tell(request, source); + } + } + + final class Caching extends AbstractAction { + public Caching(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (SpeechSynthesizerResponse.class.equals(klass)) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + final DiskCacheRequest request = new DiskCacheRequest(response.get()); + getCache().tell(request, source); + } else if (Tag.class.equals(klass)) { + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + // Parse the URL. + final String text = verb.text(); + if (text != null && !text.isEmpty()) { + // Try to cache the media. + URI target = null; + try { + target = URI.create(text); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + final DiskCacheRequest request = new DiskCacheRequest(uri); + getCache().tell(request, source); + } else { + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); + } + } + } + } + + final class Playing extends AbstractAction { + public Playing(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (DiskCacheResponse.class.equals(klass)) { + // Parse the loop attribute. + int loop = 1; + final Attribute attribute = verb.attribute("loop"); + if (attribute != null) { + final String number = attribute.value(); + if (number != null && !number.isEmpty()) { + try { + loop = Integer.parseInt(number); + } catch (final NumberFormatException ignored) { + final NotificationsDao notifications = storage.getNotificationsDao(); + Notification notification = null; + if (Verbs.say.equals(verb.name())) { + notification = notification(WARNING_NOTIFICATION, 13510, loop + " is an invalid loop value."); + notifications.addNotification(notification); + } else if (Verbs.play.equals(verb.name())) { + notification = notification(WARNING_NOTIFICATION, 13410, loop + " is an invalid loop value."); + notifications.addNotification(notification); + } + } + } + } + final DiskCacheResponse response = (DiskCacheResponse) message; + final Play play = new Play(response.get(), loop); + call.tell(play, source); + } + } + } + + String hash(Object message) { + Map details = getSynthesizeDetails(message); + if (details == null) { + if (logger.isInfoEnabled()) { + logger.info("Cannot generate hash, details are null"); + } + return null; + } + String voice = details.get("voice"); + String language = details.get("language"); + String text = details.get("text"); + return HashGenerator.hashMessage(voice, language, text); + } + + Map getSynthesizeDetails(final Object message) { + final Class klass = message.getClass(); + + Map details = new HashMap(); + + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } else { + return null; + } + if (!Verbs.say.equals(verb.name())) + return null; + + // Parse the voice attribute. + String voice = "man"; + Attribute attribute = verb.attribute("voice"); + if (attribute != null) { + voice = attribute.value(); + if (voice != null && !voice.isEmpty()) { + if (!"man".equals(voice) && !"woman".equals(voice)) { + final Notification notification = notification(WARNING_NOTIFICATION, 13511, voice + + " is an invalid voice value."); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + voice = "man"; + } + } else { + voice = "man"; + } + } + // Parse the language attribute. + String language = "en"; + attribute = verb.attribute(GatherAttributes.ATTRIBUTE_LANGUAGE); + if (attribute != null) { + language = attribute.value(); + if (language != null && !language.isEmpty()) { + if (!synthesizerInfo.languages().contains(language)) { + language = "en"; + } + } else { + language = "en"; + } + } + // Synthesize. + String text = verb.text(); + + details.put("voice", voice); + details.put("language", language); + details.put("text", text); + + return details; + + } + + final class Synthesizing extends AbstractAction { + public Synthesizing(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + + final Class klass = message.getClass(); + + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + + Map details = getSynthesizeDetails(verb); + if (details != null && !details.isEmpty() && details.get("text") != null) { + String voice = details.get("voice"); + String language = details.get("language"); + String text = details.get("text"); + final SpeechSynthesizerRequest synthesize = new SpeechSynthesizerRequest(voice, language, text); + getSynthesizer().tell(synthesize, source); + } else { + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); + } + } + } + + final class HangingUp extends AbstractAction { + public HangingUp(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + // Hang up the call. + if (ParserFailed.class.equals(klass)) { + call.tell(new Hangup("Problem_to_parse_downloaded_RCML"), source); + } else if (CallManagerResponse.class.equals(klass)) { + String reason = ((CallManagerResponse)message).cause().getMessage().replaceAll("\\s","_"); + call.tell(new Hangup(reason), source); + } else if (message instanceof SmsServiceResponse) { + //Blocked SMS Session request + call.tell(new Hangup(((SmsServiceResponse)message).cause().getMessage()), self()); + } else if (Tag.class.equals(klass) && Verbs.hangup.equals(verb.name())) { + Integer sipResponse = outboundCallResponse != null ? outboundCallResponse : SipServletResponse.SC_REQUEST_TERMINATED; + call.tell(new Hangup(sipResponse), source); + } else { + call.tell(new Hangup(outboundCallResponse), source); + } + } + } + + final class Redirecting extends AbstractAction { + public Redirecting(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + final NotificationsDao notifications = storage.getNotificationsDao(); + String method = "POST"; + Attribute attribute = verb.attribute(GatherAttributes.ATTRIBUTE_METHOD); + if (attribute != null) { + method = attribute.value(); + if (method != null && !method.isEmpty()) { + if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { + final Notification notification = notification(WARNING_NOTIFICATION, 13710, method + + " is not a valid HTTP method for "); + notifications.addNotification(notification); + method = "POST"; + } + } else { + method = "POST"; + } + } + final String text = verb.text(); + if (text != null && !text.isEmpty()) { + // Try to redirect. + URI target = null; + try { + target = URI.create(text); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + final List parameters = parameters(); + request = new HttpRequestDescriptor(uri, method, parameters); + downloader.tell(request, source); + } else { + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); + } + } + } + + abstract class AbstractGatherAction extends AbstractAction { + public AbstractGatherAction(final ActorRef source) { + super(source); + } + + protected String finishOnKey(final Tag container) { + String finishOnKey = "#"; + Attribute attribute = container.attribute(GatherAttributes.ATTRIBUTE_FINISH_ON_KEY); + if (attribute != null) { + finishOnKey = attribute.value(); + if (finishOnKey != null && !finishOnKey.isEmpty()) { + if (!PATTERN.matcher(finishOnKey).matches()) { + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 13310, finishOnKey + + " is not a valid finishOnKey value"); + notifications.addNotification(notification); + finishOnKey = "#"; + } + } else { + finishOnKey = "#"; + } + } + return finishOnKey; + } + } + + final class ProcessingGatherChildren extends AbstractGatherAction { + public ProcessingGatherChildren(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + processingGather = true; + final Class klass = message.getClass(); + final NotificationsDao notifications = storage.getNotificationsDao(); + if (SpeechSynthesizerResponse.class.equals(klass)) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + final DiskCacheRequest request = new DiskCacheRequest(response.get()); + getCache().tell(request, source); + } else { + if (Tag.class.equals(klass)) { + verb = (Tag) message; + gatherPrompts = new ArrayList(); + gatherChildren = new ArrayList(verb.children()); + } else if (DiskCacheResponse.class.equals(klass)) { + if (gatherPrompts == null) + gatherPrompts = new ArrayList(); + if (gatherChildren == null) + gatherChildren = new ArrayList(verb.children()); + final DiskCacheResponse response = (DiskCacheResponse) message; + final URI uri = response.get(); + Tag child = null; + if (!gatherChildren.isEmpty()) + child = gatherChildren.remove(0); + // Parse the loop attribute. + int loop = 1; + Attribute attribute = null; + if (child != null) + attribute = child.attribute("loop"); + if (attribute != null) { + final String number = attribute.value(); + if (number != null && !number.isEmpty()) { + try { + loop = Integer.parseInt(number); + } catch (final NumberFormatException ignored) { + Notification notification = null; + if (Verbs.say.equals(child.name())) { + notification = notification(WARNING_NOTIFICATION, 13322, loop + + " is an invalid loop value."); + notifications.addNotification(notification); + } + } + } + } + for (int counter = 0; counter < loop; counter++) { + gatherPrompts.add(uri); + } + } + for (int index = 0; index < gatherChildren.size(); index++) { + final Tag child = gatherChildren.get(index); + if (Verbs.play.equals(child.name())) { + final String text = child.text(); + if (text != null && !text.isEmpty()) { + URI target = null; + try { + target = URI.create(text); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 13325, text + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + // Cache the prompt. + final DiskCacheRequest request = new DiskCacheRequest(uri); + getCache().tell(request, source); + break; + } + } else if (Verbs.say.equals(child.name())) { + // Parse the voice attribute. + String voice = "man"; + Attribute attribute = child.attribute("voice"); + if (attribute != null) { + voice = attribute.value(); + if (voice != null && !voice.isEmpty()) { + if (!"man".equals(voice) && !"woman".equals(voice)) { + final Notification notification = notification(WARNING_NOTIFICATION, 13321, voice + + " is an invalid voice value."); + notifications.addNotification(notification); + voice = "man"; + } + } else { + voice = "man"; + } + } + // Parse the language attribute. + String language = "en"; + attribute = child.attribute("language"); + if (attribute != null) { + language = attribute.value(); + if (language != null && !language.isEmpty()) { + if (!synthesizerInfo.languages().contains(language)) { + language = "en"; + } + } else { + language = "en"; + } + } + String text = child.text(); + if (text != null && !text.isEmpty()) { + // final SpeechSynthesizerRequest synthesize = new SpeechSynthesizerRequest(voice, language, text); + // synthesizer.tell(synthesize, source); + // break; + String hash = hash(child); + DiskCacheRequest request = new DiskCacheRequest(hash); + getCache().tell(request, source); + break; + } + } else if (Verbs.pause.equals(child.name())) { + int length = 1; + final Attribute attribute = child.attribute("length"); + if (attribute != null) { + final String number = attribute.value(); + if (number != null && !number.isEmpty()) { + try { + length = Integer.parseInt(number); + } catch (final NumberFormatException ignored) { + } + } + } + String path = configuration.subset("runtime-settings").getString("prompts-uri"); + if (!path.endsWith("/")) { + path += "/"; + } + path += "one-second-silence.wav"; + final URI uri = UriUtils.resolve(new URI(path)); + for (int counter = 0; counter < length; counter++) { + gatherPrompts.add(uri); + } + } + } + // Make sure we don't leave any pauses at the beginning + // since we can't concurrently modify the list. + if (!gatherChildren.isEmpty()) { + Tag child = null; + do { + child = gatherChildren.get(0); + if (child != null) { + if (Verbs.pause.equals(child.name())) { + gatherChildren.remove(0); + } + } + } while (Verbs.pause.equals(child.name())); + } + // Start gathering. + if (gatherChildren.isEmpty()) { + if (gatherVerb != null) + verb = gatherVerb; + final StartGathering start = StartGathering.instance(); + source.tell(start, source); + processingGather = false; + } + } + } + } + + final class Gathering extends AbstractGatherAction { + public Gathering(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + + // check mandatory attribute partialResultCallback + Attribute partialResultCallbackAttr = verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK); + final NotificationsDao notifications = storage.getNotificationsDao(); + // parse attribute "input" + Attribute typeAttr = verb.attribute(GatherAttributes.ATTRIBUTE_INPUT); + Collect.Type inputType = null; + if (typeAttr == null) { + inputType = Collect.Type.DTMF; + } else { + inputType = Collect.Type.parseOrDefault(typeAttr.value(), Collect.Type.DTMF); + } + + if (inputType.equals(Collect.Type.SPEECH) || inputType.equals(Collect.Type.DTMF_SPEECH)) { + ExtensionController ec = ExtensionController.getInstance(); + final IExtensionFeatureAccessRequest far = new FeatureAccessRequest(FeatureAccessRequest.Feature.ASR, accountId); + ExtensionResponse er = ec.executePreInboundAction(far, extensions); + if (!er.isAllowed()) { + if (logger.isDebugEnabled()) { + final String errMsg = "ASR feature is not allowed"; + logger.debug(errMsg); + } + String errMsg = "ASR feature is not allowed"; + notification(WARNING_NOTIFICATION, 11001, errMsg); + call.tell(new Hangup(errMsg), source); + return; + } + ec.executePostInboundAction(far, extensions); + } + + // parse attribute "language" + Attribute langAttr = verb.attribute(GatherAttributes.ATTRIBUTE_LANGUAGE); + String defaultLang = restcommConfiguration.getMgAsr().getDefaultLanguage(); + String lang = parseAttrLanguage(langAttr, defaultLang); + + // parse attribute "hints" + String hints = null; + Attribute hintsAttr = verb.attribute(GatherAttributes.ATTRIBUTE_HINTS); + if (hintsAttr != null && !StringUtils.isEmpty(hintsAttr.value())) { + hints = hintsAttr.value(); + } else if (inputType != Collect.Type.DTMF) { + logger.warning("'{}' attribute is null or empty", GatherAttributes.ATTRIBUTE_HINTS); + } + + // Parse finish on key. + finishOnKey = finishOnKey(verb); + // Parse the number of digits. + Attribute attribute = verb.attribute(GatherAttributes.ATTRIBUTE_NUM_DIGITS); + if (attribute != null) { + final String value = attribute.value(); + if (!StringUtils.isEmpty(value)) { + try { + numberOfDigits = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13314, numberOfDigits + + " is not a valid numDigits value"); + notifications.addNotification(notification); + } + } + } + // Parse timeout. + int timeout = restcommConfiguration.getMgAsr().getDefaultGatheringTimeout(); + attribute = verb.attribute(GatherAttributes.ATTRIBUTE_TIME_OUT); + if (attribute != null) { + final String value = attribute.value(); + if (!StringUtils.isEmpty(value)) { + try { + timeout = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13313, timeout + + " is not a valid timeout value"); + notifications.addNotification(notification); + } + } + } + // Start gathering. + final Collect collect = new Collect(restcommConfiguration.getMgAsr().getDefaultDriver(), inputType, gatherPrompts, + null, timeout, finishOnKey, numberOfDigits, lang, hints, partialResultCallbackAttr != null && !StringUtils.isEmpty(partialResultCallbackAttr.value())); + call.tell(collect, source); + // Some clean up. + gatherChildren = null; + gatherPrompts = null; + dtmfReceived = false; + collectedDigits = new StringBuffer(""); + } + + private String parseAttrLanguage(Attribute langAttr, String defaultLang) { + if (langAttr != null && !StringUtils.isEmpty(langAttr.value())) { + return restcommConfiguration.getMgAsr().getLanguages().contains(langAttr.value()) ? langAttr.value() : defaultLang; + } else { + logger.warning("Illegal or unsupported attribute value: '{}'. Will be use default value '{}'", langAttr, + defaultLang); + return defaultLang; + } + } + } + + private abstract class CallbackGatherAction extends AbstractGatherAction { + + public CallbackGatherAction(ActorRef source) { + super(source); + } + + protected void execHttpRequest(final NotificationsDao notifications, + final Attribute callbackAttr, final Attribute methodAttr, + final List parameters) { + if (callbackAttr == null) { + final Notification notification = notification(ERROR_NOTIFICATION, 11101, "Callback attribute is null"); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + logger.error("CallbackAttribute is null, CallbackGatherAction failed"); + } + String action = callbackAttr.value(); + if (StringUtils.isEmpty(action)) { + final Notification notification = notification(ERROR_NOTIFICATION, 11101, "Callback attribute value is null or empty"); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + logger.error("Action url is null or empty"); + } + URI target; + try { + target = URI.create(action); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, action + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + String method = "POST"; + if (methodAttr != null) { + method = methodAttr.value(); + if (!StringUtils.isEmpty(method)) { + if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { + final Notification notification = notification(WARNING_NOTIFICATION, 14104, method + + " is not a valid HTTP method for "); + notifications.addNotification(notification); + method = "POST"; + } + } else { + method = "POST"; + } + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + request = new HttpRequestDescriptor(uri, method, parameters); + downloader.tell(request, source); + } + } + + final class FinishGathering extends CallbackGatherAction { + + public FinishGathering(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final NotificationsDao notifications = storage.getNotificationsDao(); + + String digits = collectedDigits.toString(); + collectedDigits = new StringBuffer(); + if (logger.isInfoEnabled()) { + logger.info("Digits collected: " + digits); + } + if (digits.equals(finishOnKey)) { + digits = ""; + } + if (logger.isDebugEnabled()) { + logger.debug("Digits collected : " + digits); + } + // https://bitbucket.org/telestax/telscale-restcomm/issue/150/verb-is-looping-by-default-and-never + // If the 'timeout' is reached before the caller enters any digits, or if the caller enters the 'finishOnKey' value + // before entering any other digits, Twilio will not make a request to the 'action' URL but instead continue + // processing + // the current TwiML document with the verb immediately following the + Attribute action = verb.attribute(GatherAttributes.ATTRIBUTE_ACTION); + if (action != null && (!digits.trim().isEmpty() || !StringUtils.isEmpty(speechResult))) { + // Redirect to the action url. + if (digits.endsWith(finishOnKey)) { + final int finishOnKeyIndex = digits.lastIndexOf(finishOnKey); + digits = digits.substring(0, finishOnKeyIndex); + } + 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); + 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); + } + } + + final class PartialGathering extends CallbackGatherAction { + + public PartialGathering(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + 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 NotificationsDao notifications = storage.getNotificationsDao(); + execHttpRequest(notifications, verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK), + verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK_METHOD), parameters); + } + } + } + + final class CreatingRecording extends AbstractAction { + public CreatingRecording(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + final NotificationsDao notifications = storage.getNotificationsDao(); + String finishOnKey = "1234567890*#"; + Attribute attribute = verb.attribute(GatherAttributes.ATTRIBUTE_FINISH_ON_KEY); + if (attribute != null) { + finishOnKey = attribute.value(); + if (finishOnKey != null && !finishOnKey.isEmpty()) { + //https://github.com/RestComm/Restcomm-Connect/issues/1886 + if (!finishOnKey.equals("-1")) { + if (!PATTERN.matcher(finishOnKey).matches()) { + final Notification notification = notification(WARNING_NOTIFICATION, 13613, finishOnKey + + " is not a valid finishOnKey value"); + notifications.addNotification(notification); + //https://github.com/RestComm/Restcomm-Connect/issues/1925 + finishOnKey = "#"; + } + } + } else { + //https://github.com/RestComm/Restcomm-Connect/issues/1925 + finishOnKey = "#"; + } + } + boolean playBeep = true; + attribute = verb.attribute("playBeep"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + playBeep = Boolean.parseBoolean(value); + } + } + int maxLength = 3600; + attribute = verb.attribute("maxLength"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + maxLength = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13612, maxLength + + " is not a valid maxLength value"); + notifications.addNotification(notification); + } + } + } + int timeout = 5; + attribute = verb.attribute(GatherAttributes.ATTRIBUTE_TIME_OUT); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + timeout = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13612, timeout + + " is not a valid timeout value"); + notifications.addNotification(notification); + } + } + } + recordingMediaType = MediaAttributes.MediaType.AUDIO_ONLY; + attribute = verb.attribute("media"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + recordingMediaType = MediaAttributes.MediaType.getValueOf(value); + } catch (final IllegalArgumentException exception) { + final Notification notification = notification(WARNING_NOTIFICATION, 13612, value + + " is not a valid media value"); + notifications.addNotification(notification); + } + } + } + // Start recording. + recordingSid = Sid.generate(Sid.Type.RECORDING); + String path = configuration.subset("runtime-settings").getString("recordings-path"); + String httpRecordingUri = configuration.subset("runtime-settings").getString("recordings-uri"); + if (!path.endsWith("/")) { + path += "/"; + } + if (!httpRecordingUri.endsWith("/")) { + httpRecordingUri += "/"; + } + String fileExtension = recordingMediaType.equals(MediaAttributes.MediaType.AUDIO_ONLY) ? ".wav" : ".mp4"; + path += recordingSid.toString() + fileExtension; + httpRecordingUri += recordingSid.toString() + fileExtension; + recordingUri = URI.create(path); + try { + publicRecordingUri = UriUtils.resolve(new URI(httpRecordingUri)); + } catch (URISyntaxException e) { + logger.error("URISyntaxException when trying to resolve Recording URI: "+e); + } + Record record = null; + if (playBeep) { + final List prompts = new ArrayList(1); + path = configuration.subset("runtime-settings").getString("prompts-uri"); + if (!path.endsWith("/")) { + path += "/"; + } + path += "beep.wav"; + try { + prompts.add(UriUtils.resolve(new URI(path))); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + record = new Record(recordingUri, prompts, timeout, maxLength, finishOnKey, recordingMediaType); + } else { + record = new Record(recordingUri, timeout, maxLength, finishOnKey, recordingMediaType); + } + + call.tell(record, source); + } + } + + final class FinishRecording extends AbstractAction { + public FinishRecording(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + if (logger.isInfoEnabled()) { + logger.info("##### At FinishRecording, message: " + message.getClass()); + } + boolean amazonS3Enabled = configuration.subset("amazon-s3").getBoolean("enabled"); + + final Class klass = message.getClass(); + if (CallStateChanged.class.equals(klass)) { + final CallStateChanged event = (CallStateChanged) message; + // Update the interpreter state. + callState = event.state(); + // Update the storage. + callRecord = callRecord.setStatus(callState.toString()); + final DateTime end = DateTime.now(); + callRecord = callRecord.setEndTime(end); + recordingDuration = (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000; + callRecord = callRecord.setDuration(recordingDuration); + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + records.updateCallDetailRecord(callRecord); + // Update the application. +// callback(); + } + + Recording recording = null; + + final NotificationsDao notifications = storage.getNotificationsDao(); + // Create a record of the recording. + Double duration = WavUtils.getAudioDuration(recordingUri); + if (duration.equals(0.0)) { + if (logger.isInfoEnabled()) { + String msg = String.format("Recording file %s, duration is 0 and will return",recordingUri); + logger.info(msg); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("Recording File exists, length: " + (new File(recordingUri).length())); + logger.debug("Recording duration: " + duration); + } + + final Recording.Builder builder = Recording.builder(); + builder.setSid(recordingSid); + builder.setAccountSid(accountId); + builder.setCallSid(callInfo.sid()); + builder.setDuration(duration); + builder.setApiVersion(version); + StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/").append(accountId.toString()); + buffer.append("/Recordings/").append(recordingSid.toString()); + builder.setUri(URI.create(buffer.toString())); + recording = builder.build(); + final RecordingsDao recordings = storage.getRecordingsDao(); + recordings.addRecording(recording, recordingMediaType); + + Attribute attribute = null; + + if (checkAsrService()) { + // ASR service is enabled. Start transcription. + URI transcribeCallback = null; + attribute = verb.attribute("transcribeCallback"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + transcribeCallback = URI.create(value); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, transcribeCallback + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + } + boolean transcribe = false; + if (transcribeCallback != null) { + transcribe = true; + } else { + attribute = verb.attribute("transcribe"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + transcribe = Boolean.parseBoolean(value); + } + } + } + if (transcribe && checkAsrService()) { + final Sid sid = Sid.generate(Sid.Type.TRANSCRIPTION); + final Transcription.Builder otherBuilder = Transcription.builder(); + otherBuilder.setSid(sid); + otherBuilder.setAccountSid(accountId); + otherBuilder.setStatus(Transcription.Status.IN_PROGRESS); + otherBuilder.setRecordingSid(recordingSid); + otherBuilder.setTranscriptionText("Transcription Text not available"); + otherBuilder.setDuration(duration); + otherBuilder.setPrice(new BigDecimal("0.00")); + buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/").append(accountId.toString()); + buffer.append("/Transcriptions/").append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + otherBuilder.setUri(uri); + final Transcription transcription = otherBuilder.build(); + final TranscriptionsDao transcriptions = storage.getTranscriptionsDao(); + transcriptions.addTranscription(transcription); + try { + final Map attributes = new HashMap(); + attributes.put("callback", transcribeCallback); + attributes.put("transcription", transcription); + getAsrService().tell(new AsrRequest(new File(recordingUri), "en", attributes), source); + outstandingAsrRequests++; + } catch (final Exception exception) { + logger.error(exception.getMessage(), exception); + } + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("AsrService is not enabled"); + } + } + } + + // If action is present redirect to the action URI. + String action = null; + Attribute attribute = verb.attribute(GatherAttributes.ATTRIBUTE_ACTION); + if (attribute != null) { + action = attribute.value(); + if (action != null && !action.isEmpty()) { + URI target = null; + try { + target = URI.create(action); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, action + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + // Parse "method". + String method = "POST"; + attribute = verb.attribute(GatherAttributes.ATTRIBUTE_METHOD); + if (attribute != null) { + method = attribute.value(); + if (method != null && !method.isEmpty()) { + if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { + final Notification notification = notification(WARNING_NOTIFICATION, 13610, method + + " is not a valid HTTP method for "); + notifications.addNotification(notification); + method = "POST"; + } + } else { + method = "POST"; + } + } + final List parameters = parameters(); + if (recording != null) { + if (amazonS3Enabled) { + //If Amazon S3 is enabled the Recordings DAO uploaded the wav file to S3 and changed the URI + parameters.add(new BasicNameValuePair("RecordingUrl", recording.getFileUri().toURL().toString())); + parameters.add(new BasicNameValuePair("PublicRecordingUrl", recording.getFileUri().toURL().toString())); + } else { + // Redirect to the action url. + String httpRecordingUri = configuration.subset("runtime-settings").getString("recordings-uri"); + if (!httpRecordingUri.endsWith("/")) { + httpRecordingUri += "/"; + } + String fileExtension = recordingMediaType.equals(MediaAttributes.MediaType.AUDIO_ONLY) ? ".wav" : ".mp4"; + httpRecordingUri += recordingSid.toString() + fileExtension; + URI publicRecordingUri = UriUtils.resolve(new URI(httpRecordingUri)); + parameters.add(new BasicNameValuePair("RecordingUrl", recordingUri.toString())); + parameters.add(new BasicNameValuePair("PublicRecordingUrl", publicRecordingUri.toString())); + } + } + parameters.add(new BasicNameValuePair("RecordingDuration", Double.toString(duration))); + if (MediaGroupResponse.class.equals(klass)) { + final MediaGroupResponse response = (MediaGroupResponse) message; + Object data = response.get(); + 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); + } + downloader.tell(request, self()); + } else if (CallStateChanged.class.equals(klass)) { + parameters.add(new BasicNameValuePair("Digits", "hangup")); + request = new HttpRequestDescriptor(uri, method, parameters); + if (logger.isInfoEnabled()) { + logger.info("About to execute Record action to: "+uri); + } + downloader.tell(request, self()); + } +// final StopInterpreter stop = new StopInterpreter(); +// source.tell(stop, source); + } + } else { + //Action is null here + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); + } + // A little clean up. + recordingSid = null; + recordingUri = null; + recordingMediaType = null; + } + } + + final class CreatingSmsSession extends AbstractAction { + public CreatingSmsSession(final ActorRef source) { + super(source); + } + + @Override + public void execute(Object message) throws Exception { + // Save verb. + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + // Create a new sms session to handle the verb. + smsService.tell(new CreateSmsSession(callInfo.from(), callInfo.to(), accountId.toString(), false), source); + } + } + + final class SendingSms extends AbstractAction { + public SendingSms(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + final SmsServiceResponse response = (SmsServiceResponse) message; + final ActorRef session = response.get(); + final NotificationsDao notifications = storage.getNotificationsDao(); + // Parse "from". + String from = callInfo.to(); + Attribute attribute = verb.attribute("from"); + if (attribute != null) { + from = attribute.value(); + if (from != null && !from.isEmpty()) { + from = e164(from); + if (from == null) { + from = verb.attribute("from").value(); + final Notification notification = notification(ERROR_NOTIFICATION, 14102, from + + " is an invalid 'from' phone number."); + notifications.addNotification(notification); + sendMail(notification); + smsService.tell(new DestroySmsSession(session), source); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + } + // Parse "to". + String to = callInfo.from(); + attribute = verb.attribute("to"); + if (attribute != null) { + to = attribute.value(); + if (to != null && !to.isEmpty()) { + to = e164(to); + if (to == null) { + to = verb.attribute("to").value(); + final Notification notification = notification(ERROR_NOTIFICATION, 14101, to + + " is an invalid 'to' phone number."); + notifications.addNotification(notification); + sendMail(notification); + smsService.tell(new DestroySmsSession(session), source); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + } + // Parse text. + String body = verb.text(); + if (body == null || body.isEmpty()) { + final Notification notification = notification(ERROR_NOTIFICATION, 14103, body + " is an invalid SMS body."); + notifications.addNotification(notification); + sendMail(notification); + smsService.tell(new DestroySmsSession(session), source); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } else { + // Start observing events from the sms session. + session.tell(new Observe(source), source); + // Store the status callback in the sms session. + attribute = verb.attribute("statusCallback"); + if (attribute != null) { + String callback = attribute.value(); + if (callback != null && !callback.isEmpty()) { + URI target = null; + try { + target = URI.create(callback); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 14105, callback + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + smsService.tell(new DestroySmsSession(session), source); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + session.tell(new SmsSessionAttribute("callback", uri), source); + } + } + // Create an SMS detail record. + final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE); + final SmsMessage.Builder builder = SmsMessage.builder(); + builder.setSid(sid); + builder.setAccountSid(accountId); + builder.setApiVersion(version); + builder.setRecipient(to); + builder.setSender(from); + builder.setBody(body); + builder.setDirection(Direction.OUTBOUND_REPLY); + builder.setStatus(Status.SENDING); + builder.setPrice(new BigDecimal("0.00")); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/"); + buffer.append(accountId.toString()).append("/SMS/Messages/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + final SmsMessage record = builder.build(); + final SmsMessagesDao messages = storage.getSmsMessagesDao(); + messages.addSmsMessage(record); + // Store the sms record in the sms session. + session.tell(new SmsSessionAttribute("record", record), source); + // Send the SMS. + final SmsSessionRequest sms = new SmsSessionRequest(from, to, body, null); + session.tell(sms, source); + smsSessions.put(sid, session); + } + // Parses "action". + attribute = verb.attribute("action"); + if (attribute != null) { + String action = attribute.value(); + if (action != null && !action.isEmpty()) { + URI target = null; + try { + target = URI.create(action); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 11100, action + + " is an invalid URI."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + final URI base = request.getUri(); + final URI uri = UriUtils.resolve(base, target); + // Parse "method". + String method = "POST"; + attribute = verb.attribute("method"); + if (attribute != null) { + method = attribute.value(); + if (method != null && !method.isEmpty()) { + if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { + final Notification notification = notification(WARNING_NOTIFICATION, 14104, method + + " is not a valid HTTP method for "); + notifications.addNotification(notification); + method = "POST"; + } + } else { + method = "POST"; + } + } + // Redirect to the action url. + final List parameters = parameters(); + final String status = Status.SENDING.toString(); + parameters.add(new BasicNameValuePair("SmsStatus", status)); + request = new HttpRequestDescriptor(uri, method, parameters); + downloader.tell(request, source); + return; + } + } + // 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/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java similarity index 83% rename from restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreter.java rename to restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java index 9e7358c259..3ab740f54e 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/ConfVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java @@ -1,62 +1,4 @@ -package org.mobicents.servlet.restcomm.interpreter; - -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.play; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.say; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.configuration.Configuration; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.message.BasicNameValuePair; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.cache.DiskCache; -import org.mobicents.servlet.restcomm.cache.DiskCacheRequest; -import org.mobicents.servlet.restcomm.cache.DiskCacheResponse; -import org.mobicents.servlet.restcomm.cache.HashGenerator; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.email.Mail; -import org.mobicents.servlet.restcomm.email.MailMan; -import org.mobicents.servlet.restcomm.entities.CallDetailRecord; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.fsm.Action; -import org.mobicents.servlet.restcomm.fsm.FiniteStateMachine; -import org.mobicents.servlet.restcomm.fsm.State; -import org.mobicents.servlet.restcomm.fsm.Transition; -import org.mobicents.servlet.restcomm.http.client.Downloader; -import org.mobicents.servlet.restcomm.http.client.DownloaderResponse; -import org.mobicents.servlet.restcomm.http.client.HttpRequestDescriptor; -import org.mobicents.servlet.restcomm.http.client.HttpResponseDescriptor; -import org.mobicents.servlet.restcomm.interpreter.rcml.Attribute; -import org.mobicents.servlet.restcomm.interpreter.rcml.End; -import org.mobicents.servlet.restcomm.interpreter.rcml.GetNextVerb; -import org.mobicents.servlet.restcomm.interpreter.rcml.Parser; -import org.mobicents.servlet.restcomm.interpreter.rcml.Tag; -import org.mobicents.servlet.restcomm.interpreter.rcml.Verbs; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.telephony.CallInfo; -import org.mobicents.servlet.restcomm.telephony.CallStateChanged; -import org.mobicents.servlet.restcomm.telephony.ConferenceResponse; -import org.mobicents.servlet.restcomm.telephony.CreateMediaGroup; -import org.mobicents.servlet.restcomm.telephony.DestroyWaitUrlConfMediaGroup; -import org.mobicents.servlet.restcomm.telephony.MediaGroupResponse; -import org.mobicents.servlet.restcomm.telephony.MediaGroupStateChanged; -import org.mobicents.servlet.restcomm.telephony.Play; -import org.mobicents.servlet.restcomm.telephony.StartMediaGroup; -import org.mobicents.servlet.restcomm.telephony.StopMediaGroup; -import org.mobicents.servlet.restcomm.tts.api.GetSpeechSynthesizerInfo; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerInfo; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerRequest; -import org.mobicents.servlet.restcomm.tts.api.SpeechSynthesizerResponse; +package org.restcomm.connect.interpreter; import akka.actor.Actor; import akka.actor.ActorRef; @@ -67,17 +9,75 @@ import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; - import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; +import org.apache.commons.configuration.Configuration; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.cache.DiskCacheFactory; +import org.restcomm.connect.commons.cache.DiskCacheRequest; +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; +import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +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; +import org.restcomm.connect.email.EmailService; +import org.restcomm.connect.email.api.EmailRequest; +import org.restcomm.connect.email.api.Mail; +import org.restcomm.connect.http.client.Downloader; +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.rcml.Attribute; +import org.restcomm.connect.interpreter.rcml.End; +import org.restcomm.connect.interpreter.rcml.GetNextVerb; +import org.restcomm.connect.interpreter.rcml.Parser; +import org.restcomm.connect.interpreter.rcml.Tag; +import org.restcomm.connect.interpreter.rcml.Verbs; +import org.restcomm.connect.mscontrol.api.messages.CreateMediaGroup; +import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; +import org.restcomm.connect.mscontrol.api.messages.MediaGroupStateChanged; +import org.restcomm.connect.mscontrol.api.messages.MediaServerControllerResponse; +import org.restcomm.connect.mscontrol.api.messages.Play; +import org.restcomm.connect.mscontrol.api.messages.StartMediaGroup; +import org.restcomm.connect.mscontrol.api.messages.StopMediaGroup; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallStateChanged; +import org.restcomm.connect.telephony.api.DestroyWaitUrlConfMediaGroup; +import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; +import org.restcomm.connect.tts.api.SpeechSynthesizerInfo; +import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; +import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +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; - private static final String EMAIL_SENDER = "restcomm@restcomm.org"; - private static final String EMAIL_SUBJECT = "RestComm Error Notification - Attention Required"; + static String EMAIL_SENDER; + // Logger. private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // States for the FSM. @@ -106,7 +106,7 @@ public class ConfVoiceInterpreter extends UntypedActor { // The downloader will fetch resources for us using HTTP. private final ActorRef downloader; // The mail man that will deliver e-mail. - private ActorRef mailer; + private ActorRef mailerNotify = null; // The storage engine. private final DaoManager storage; @@ -146,9 +146,7 @@ public class ConfVoiceInterpreter extends UntypedActor { private ActorRef originalInterpreter; - 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(); @@ -230,16 +228,15 @@ 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")); - this.mailer = mailer(configuration.subset("smtp")); final Configuration runtime = configuration.subset("runtime-settings"); String path = runtime.getString("cache-path"); if (!path.endsWith("/")) { @@ -255,32 +252,41 @@ 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) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { - return new DiskCache(path, uri, true); + return new DiskCacheFactory(configuration).getDiskCache(path, uri); } - })); + }); + return getContext().actorOf(props); } private ActorRef downloader() { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { return new Downloader(); } - })); + }); + return getContext().actorOf(props); } private String e164(final String number) { @@ -296,20 +302,20 @@ private String e164(final String number) { private void invalidVerb(final Tag verb) { final ActorRef self = self(); // Get the next verb. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, self); } - private ActorRef mailer(final Configuration configuration) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + ActorRef mailer(final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override - public UntypedActor create() throws Exception { - return new MailMan(configuration); + public Actor create() throws Exception { + return new EmailService(configuration); } - })); + }); + return getContext().actorOf(props); } private Notification notification(final int log, final int error, final String message) { @@ -386,15 +392,15 @@ public void onReceive(final Object message) throws Exception { fsm.transition(message, finished); } } - } else if (ConferenceResponse.class.equals(klass)) { + } else if (MediaServerControllerResponse.class.equals(klass)) { if (acquiringConfMediaGroup.equals(state)) { fsm.transition(message, initializingConfMediaGroup); } } else if (DownloaderResponse.class.equals(klass)) { downloaderResponse = (DownloaderResponse) message; - if (logger.isDebugEnabled()) { + if (logger.isDebugEnabled()){ logger.debug("response succeeded " + downloaderResponse.succeeded() + ", statusCode " - + downloaderResponse.get().getStatusCode()); + + downloaderResponse.get().getStatusCode()); } if (downloaderResponse.succeeded() && HttpStatus.SC_OK == downloaderResponse.get().getStatusCode()) { fsm.transition(message, acquiringConfMediaGroup); @@ -424,7 +430,9 @@ public void onReceive(final Object message) throws Exception { } } else if (DiskCacheResponse.class.equals(klass)) { final DiskCacheResponse response = (DiskCacheResponse) message; - logger.info("DiskCacheResponse " + response.succeeded() + " error=" + response.error()); + if(logger.isInfoEnabled()){ + logger.info("DiskCacheResponse " + response.succeeded() + " error=" + response.error()); + } if (response.succeeded()) { if (caching.equals(state) || checkingCache.equals(state)) { if (play.equals(verb.name()) || say.equals(verb.name())) { @@ -441,8 +449,9 @@ public void onReceive(final Object message) throws Exception { } } else if (Tag.class.equals(klass)) { verb = (Tag) message; - - logger.info("ConfVoiceInterpreter verb = " + verb.name()); + if(logger.isInfoEnabled()) { + logger.info("ConfVoiceInterpreter verb = " + verb.name()); + } if (Verbs.dial.equals(verb.name())) originalInterpreter.tell(new Exception("Dial verb not supported"), source); @@ -497,15 +506,15 @@ private List parameters() { } private ActorRef parser(final String xml) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { - return new Parser(xml); + return new Parser(xml, self()); } - })); + }); + return getContext().actorOf(props); } private void postCleanup() { @@ -530,6 +539,8 @@ private void sendMail(final Notification notification) { if (emailAddress == null || emailAddress.isEmpty()) { return; } + + final String EMAIL_SUBJECT = "RestComm Error Notification - Attention Required"; final StringBuilder buffer = new StringBuilder(); buffer.append("").append("Sid: ").append("
      "); buffer.append(notification.getSid().toString()).append("
      "); @@ -559,22 +570,25 @@ private void sendMail(final Notification notification) { buffer.append(notification.getResponseHeaders()).append("
      "); buffer.append("").append("Response Body: ").append("
      "); buffer.append(notification.getResponseBody()).append("
      "); - final Mail email = new Mail(EMAIL_SENDER, emailAddress, EMAIL_SUBJECT, buffer.toString()); - mailer.tell(email, self()); + final Mail emailMsg = new Mail(EMAIL_SENDER,emailAddress,EMAIL_SUBJECT, buffer.toString()); + if (mailerNotify == null){ + mailerNotify = mailer(configuration.subset("smtp-notify")); + } + mailerNotify.tell(new EmailRequest(emailMsg), self()); } private ActorRef tts(final Configuration configuration) { final String classpath = configuration.getString("[@class]"); - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public Actor create() throws Exception { return (UntypedActor) Class.forName(classpath).getConstructor(Configuration.class).newInstance(configuration); } - })); + }); + return getContext().actorOf(props); } private abstract class AbstractAction implements Action { @@ -591,7 +605,6 @@ public AcquiringSpeechSynthesizerInfo(final ActorRef source) { super(source); } - @SuppressWarnings({ "unchecked" }) @Override public void execute(final Object message) throws Exception { final StartInterpreter request = (StartInterpreter) message; @@ -619,7 +632,7 @@ public InitializingConferenceMediaGroup(final ActorRef source) { @SuppressWarnings("unchecked") @Override public void execute(final Object message) throws Exception { - final ConferenceResponse response = (ConferenceResponse) message; + final MediaServerControllerResponse response = (MediaServerControllerResponse) message; conferenceMediaGroup = response.get(); conferenceMediaGroup.tell(new Observe(source), source); final StartMediaGroup request = new StartMediaGroup(); @@ -658,8 +671,6 @@ public Ready(final ActorRef source) { @Override public void execute(final Object message) throws Exception { - final UntypedActorContext context = getContext(); - final State state = fsm.state(); if (parser == null) { response = downloaderResponse.get(); @@ -671,13 +682,13 @@ public void execute(final Object message) throws Exception { } else if (type.contains("text/plain")) { parser = parser("" + response.getContentAsString() + ""); } else { - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } } // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -689,7 +700,6 @@ public NotFound(final ActorRef source) { @Override public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); final DownloaderResponse response = (DownloaderResponse) message; if (logger.isDebugEnabled()) { logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); @@ -699,7 +709,7 @@ public void execute(final Object message) throws Exception { final NotificationsDao notifications = storage.getNotificationsDao(); notifications.addNotification(notification); // Hang up the call. - conference.tell(new org.mobicents.servlet.restcomm.telephony.NotFound(), source); + conference.tell(new org.restcomm.connect.telephony.api.NotFound(), source); } } @@ -708,22 +718,16 @@ public CheckCache(final ActorRef source) { super(source); } - @SuppressWarnings("unchecked") @Override public void execute(final Object message) throws Exception { final Class klass = message.getClass(); if (Tag.class.equals(klass)) { verb = (Tag) message; } - // else { - // logger.info("Can't check cache, message not verb. Moving to the next verb"); - // // final GetNextVerb next = GetNextVerb.instance(); - // // parser.tell(next, source); - // return; - // } + String hash = hash(verb); DiskCacheRequest request = new DiskCacheRequest(hash); - if (logger.isErrorEnabled()) { + if (logger.isInfoEnabled()) { logger.info("Checking cache for hash: " + hash); } cache.tell(request, source); @@ -759,7 +763,7 @@ public void execute(final Object message) throws Exception { final NotificationsDao notifications = storage.getNotificationsDao(); notifications.addNotification(notification); sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -769,7 +773,7 @@ public void execute(final Object message) throws Exception { cache.tell(request, source); } else { // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -905,7 +909,7 @@ public void execute(final Object message) throws Exception { synthesizer.tell(synthesize, source); } else { // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -948,7 +952,7 @@ public void execute(final Object message) throws Exception { final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); notifications.addNotification(notification); sendMail(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -959,7 +963,7 @@ public void execute(final Object message) throws Exception { downloader.tell(request, source); } else { // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -972,9 +976,9 @@ public Finished(final ActorRef source) { @Override public void execute(final Object message) throws Exception { - final Class klass = message.getClass(); - - logger.info("Finished called for ConfVoiceInterpreter"); + if(logger.isInfoEnabled()) { + logger.info("Finished called for ConfVoiceInterpreter"); + } final StopMediaGroup stop = new StopMediaGroup(); // Destroy the media group(s). @@ -982,14 +986,15 @@ public void execute(final Object message) throws Exception { conferenceMediaGroup.tell(stop, source); final DestroyWaitUrlConfMediaGroup destroy = new DestroyWaitUrlConfMediaGroup(conferenceMediaGroup); conference.tell(destroy, source); - conferenceMediaGroup = null; +// conferenceMediaGroup = null; } // TODO should the dependencies be stopped here? // Stop the dependencies. final UntypedActorContext context = getContext(); - context.stop(mailer); + if (mailerNotify != null) + context.stop(mailerNotify); context.stop(downloader); context.stop(cache); context.stop(synthesizer); @@ -998,27 +1003,22 @@ public void execute(final Object message) throws Exception { } } - /* - * (non-Javadoc) - * @see akka.actor.UntypedActor#postStop() - */ @Override public void postStop() { - final StopMediaGroup stop = new StopMediaGroup(); + // final StopMediaGroup stop = new StopMediaGroup(); // Destroy the media group(s). - if (conferenceMediaGroup != null) { - conferenceMediaGroup.tell(stop, source); - } - if (conference != null && !conference.isTerminated()) { - final DestroyWaitUrlConfMediaGroup destroy = new DestroyWaitUrlConfMediaGroup(conferenceMediaGroup); - conference.tell(destroy, source); - } - - if (conferenceMediaGroup != null && !conferenceMediaGroup.isTerminated()) - getContext().stop(conferenceMediaGroup); - - conferenceMediaGroup = null; - + // if (conferenceMediaGroup != null) { + // conferenceMediaGroup.tell(stop, source); + // } + // if (conference != null && !conference.isTerminated()) { + // final DestroyWaitUrlConfMediaGroup destroy = new DestroyWaitUrlConfMediaGroup(conferenceMediaGroup); + // conference.tell(destroy, source); + // } + // + // if (conferenceMediaGroup != null && !conferenceMediaGroup.isTerminated()) + // getContext().stop(conferenceMediaGroup); + // + // conferenceMediaGroup = null; super.postStop(); } } 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/Fork.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/Fork.java new file mode 100644 index 0000000000..25b27a5a2f --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/Fork.java @@ -0,0 +1,32 @@ +/* + * 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 org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public final class Fork { + public Fork() { + super(); + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectionResult.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectionResult.java new file mode 100644 index 0000000000..e0564169f2 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectionResult.java @@ -0,0 +1,57 @@ +/* + * 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 org.restcomm.connect.dao.entities.IncomingPhoneNumber; + +public class NumberSelectionResult { + + IncomingPhoneNumber number; + Boolean organizationFiltered = false; + ResultType type; + + public NumberSelectionResult(IncomingPhoneNumber number, Boolean organizationFiltered, ResultType type) { + this.number = number; + this.organizationFiltered = organizationFiltered; + this.type = type; + } + + public IncomingPhoneNumber getNumber() { + return number; + } + + public Boolean getOrganizationFiltered() { + return organizationFiltered; + } + + public void setOrganizationFiltered(Boolean organizationFiltered) { + this.organizationFiltered = organizationFiltered; + } + + public ResultType getType() { + return type; + } + + public void setType(ResultType type) { + this.type = type; + } + + +} \ No newline at end of file diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectorService.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectorService.java new file mode 100644 index 0000000000..f5477513ae --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/NumberSelectorService.java @@ -0,0 +1,429 @@ +/* + * 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 java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.IncomingPhoneNumbersDao; +import org.restcomm.connect.dao.entities.IncomingPhoneNumber; +import org.restcomm.connect.dao.entities.IncomingPhoneNumberFilter; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; + +/** + * This Service will be used in different protocol scenarios to find if some + * application is associated to the incoming session/number. + * + * Different queries to IncomingPhoneNumbersDao will be performed to try + * locating the proper application. + * + * + * Is expected that protocol scenario will provide meaningful Organization + * details for source and destination. If protocol doesnt support Organizations + * yet, then null values are allowed, but Regexes will not be evaluated in these + * cases. + */ +public class NumberSelectorService { + + private static Logger logger = Logger.getLogger(NumberSelectorService.class); + + private IncomingPhoneNumbersDao numbersDao; + + public NumberSelectorService(IncomingPhoneNumbersDao numbersDao) { + this.numbersDao = numbersDao; + } + + /** + * + * @param phone the original incoming phone number + * @return a list of strings to match number based on different formats + */ + private List createPhoneQuery(String phone) { + List numberQueries = new ArrayList(10); + //add the phone itself like it is first + numberQueries.add(phone); + //try adding US format if number doesnt contain *# + if (!(phone.contains("*") || phone.contains("#"))) { + try { + // Format the destination to an E.164 phone number. + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + String usFormatNum = phoneNumberUtil.format(phoneNumberUtil.parse(phone, "US"), PhoneNumberUtil.PhoneNumberFormat.E164); + if (!numberQueries.contains(usFormatNum)) { + if (logger.isDebugEnabled()) { + logger.debug("Adding US Format num to queries:" + usFormatNum); + } + numberQueries.add(usFormatNum); + } + } catch (NumberParseException e) { + //logger.error("Exception when try to format : " + e); + } + } + //here we deal with different + prefix scnearios. + //different providers will trigger calls with different formats + //basiaclly we try with a leading + if original number doesnt have it, + //and remove it if it has it. + if (phone.startsWith("+")) { + //remove the (+) and check if exists + String noPlusNum = phone.replaceFirst("\\+", ""); + if (!numberQueries.contains(noPlusNum)) { + if (logger.isDebugEnabled()) { + logger.debug("Adding No Plus Num:" + noPlusNum); + } + numberQueries.add(noPlusNum); + } + } else { + String plusNum = "+".concat(phone); + if (!numberQueries.contains(plusNum)) { + if (logger.isDebugEnabled()) { + logger.debug("Adding Plus Num:" + plusNum); + } + numberQueries.add(plusNum); + } + } + return numberQueries; + } + + /** + * Here we expect a perfect match in DB. + * + * Several rules regarding organization scoping will be applied in the DAO + * filter to ensure only applicable numbers in DB are retrieved. + * + * @param number the number to match against IncomingPhoneNumbersDao + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @return the matched number, null if not matched. + */ + private NumberSelectionResult findSingleNumber(String number, + Sid sourceOrganizationSid, Sid destinationOrganizationSid, Set modifiers) { + NumberSelectionResult matchedNumber = new NumberSelectionResult(null, false, null); + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byPhoneNumber(number); + int unfilteredCount = numbersDao.getTotalIncomingPhoneNumbers(filterBuilder.build()); + if (unfilteredCount > 0) { + if (destinationOrganizationSid != null) { + filterBuilder.byOrgSid(destinationOrganizationSid.toString()); + } else if ((modifiers != null) && (modifiers.contains(SearchModifier.ORG_COMPLIANT))){ + //restrict search to non SIP numbers + logger.debug("Organizations are null, restrict PureSIP numbers."); + filterBuilder.byPureSIP(Boolean.FALSE); + } + + //this rule forbids using PureSIP numbers if organizations doesnt match + //this means only external provider numbers will be evaluated in DB + if (sourceOrganizationSid != null + && !sourceOrganizationSid.equals(destinationOrganizationSid)) { + filterBuilder.byPureSIP(Boolean.FALSE); + } + + IncomingPhoneNumberFilter numFilter = filterBuilder.build(); + if (logger.isDebugEnabled()) { + logger.debug("Searching with filter:" + numFilter); + } + List matchedNumbers = numbersDao.getIncomingPhoneNumbersByFilter(numFilter); + if (logger.isDebugEnabled()) { + logger.debug("Num of results:" + matchedNumbers.size() + ".unfilteredCount:" + unfilteredCount); + } + //we expect a perfect match, so first result taken + if (matchedNumbers != null && matchedNumbers.size() > 0) { + if (logger.isDebugEnabled()) { + logger.debug("Matched number with filter:" + matchedNumbers.get(0).toString()); + } + + matchedNumber = new NumberSelectionResult(matchedNumbers.get(0), Boolean.FALSE, ResultType.REGULAR); + } else { + //without organization fileter we had results,so this is + //marked as filtered by organization + matchedNumber.setOrganizationFiltered(Boolean.TRUE); + } + } + return matchedNumber; + } + + /** + * Iterates over the list of given numbers, and returns the first matching. + * + * @param numberQueries the list of numbers to attempt + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @return the matched number, null if not matched. + */ + private NumberSelectionResult findByNumber(List numberQueries, + Sid sourceOrganizationSid, Sid destinationOrganizationSid, Set modifiers) { + Boolean orgFiltered = false; + NumberSelectionResult matchedNumber = new NumberSelectionResult(null, orgFiltered, null); + int i = 0; + while (matchedNumber.number == null && i < numberQueries.size()) { + matchedNumber = findSingleNumber(numberQueries.get(i), + sourceOrganizationSid, destinationOrganizationSid, modifiers); + //preserve the orgFiltered flag along the queries + if (matchedNumber.getOrganizationFiltered()) { + orgFiltered = true; + } + i = i + 1; + } + matchedNumber.setOrganizationFiltered(orgFiltered); + return matchedNumber; + } + + /** + * @param phone + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @return + */ + public IncomingPhoneNumber searchNumber(String phone, + Sid sourceOrganizationSid, Sid destinationOrganizationSid) { + return searchNumber(phone, sourceOrganizationSid, destinationOrganizationSid, new HashSet<>(Arrays.asList(SearchModifier.ORG_COMPLIANT))); + } + + /** + * @param phone + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @param modifiers + * @return + */ + public IncomingPhoneNumber searchNumber(String phone, + Sid sourceOrganizationSid, Sid destinationOrganizationSid, Set modifiers) { + NumberSelectionResult searchNumber = searchNumberWithResult(phone, sourceOrganizationSid, destinationOrganizationSid, modifiers); + return searchNumber.number; + } + + /** + * + * @param result whether the call should be rejected depending on results + * found + * @param srcOrg + * @param destOrg + * @return + */ + public boolean isFailedCall(NumberSelectionResult result, Sid srcOrg, Sid destOrg) { + boolean failCall = false; + + if (result.getNumber() == null) { + if (!destOrg.equals(srcOrg) + && result.getOrganizationFiltered()) { + failCall = true; + } + } + + return failCall; + } + + /** + * The main logic is: -Find a perfect match in DB using different formats. + * -If not matched, use available Regexes in the organization. -If not + * matched, try with the special * match. + * + * @param phone + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @return + */ + public NumberSelectionResult searchNumberWithResult(String phone, + Sid sourceOrganizationSid, Sid destinationOrganizationSid){ + return searchNumberWithResult(phone, sourceOrganizationSid, destinationOrganizationSid, new HashSet<>(Arrays.asList(SearchModifier.ORG_COMPLIANT))); + } + + /** + * The main logic is: -Find a perfect match in DB using different formats. + * -If not matched, use available Regexes in the organization. -If not + * matched, try with the special * match. + * + * @param phone + * @param sourceOrganizationSid + * @param destinationOrganizationSid + * @param modifiers + * @return + */ + public NumberSelectionResult searchNumberWithResult(String phone, + Sid sourceOrganizationSid, Sid destinationOrganizationSid, Set modifiers) { + if (logger.isDebugEnabled()) { + logger.debug("getMostOptimalIncomingPhoneNumber: " + phone + + ",srcOrg:" + sourceOrganizationSid + + ",destOrg:" + destinationOrganizationSid); + } + List numberQueries = createPhoneQuery(phone); + + NumberSelectionResult numberfound = findByNumber(numberQueries, sourceOrganizationSid, destinationOrganizationSid, modifiers); + if (numberfound.number == null) { + //only use regex if perfect match didnt worked + if (destinationOrganizationSid != null + && (sourceOrganizationSid == null || destinationOrganizationSid.equals(sourceOrganizationSid)) + && phone.matches("[\\d,*,#,+]+")) { + //check regex if source and dest orgs are the same + //only use regex if org available + //check if there is a Regex match only if parameter is a String aka phone Number + NumberSelectionResult regexFound = findByRegex(numberQueries, sourceOrganizationSid, destinationOrganizationSid); + if (regexFound.getNumber() != null) { + numberfound = regexFound; + } + if (numberfound.number == null) { + //if no regex match found, try with special star number in the end + NumberSelectionResult starfound = findSingleNumber("*", sourceOrganizationSid, destinationOrganizationSid, modifiers); + if (starfound.number != null) { + numberfound = new NumberSelectionResult(starfound.number, false, ResultType.REGEX); + } + } + } + } + if (numberfound.number == null) { + if (logger.isDebugEnabled()) { + StringBuffer stringBuffer = new StringBuffer(); + + stringBuffer.append("NumberSelectionService didn't match a number because: "); + + if (destinationOrganizationSid == null) { + stringBuffer.append(" - Destination Org is null - "); + } else if (sourceOrganizationSid != null && !destinationOrganizationSid.equals(sourceOrganizationSid)) { + stringBuffer.append(" - Source Org is NOT null and DOESN'T match the Destination Org - "); + } else if (!phone.matches("[\\d,*,#,+]+")) { + String msg = String.format(" - Phone %s doesn't match regex \"[\\\\d,*,#,+]+\" - ", phone); + stringBuffer.append(msg); + } else { + String msg = String.format(" - Phone %s didn't match any of the Regex - ",phone); + stringBuffer.append(msg); + } + logger.debug(stringBuffer.toString()); + } + } + return numberfound; + } + + /** + * Used to order a collection by the size of PhoneNumber String + */ + class NumberLengthComparator implements Comparator { + + @Override + public int compare(IncomingPhoneNumber o1, IncomingPhoneNumber o2) { + //put o2 first to make longest first in coll + int comparison = Integer.compare(o2.getPhoneNumber().length(), o1.getPhoneNumber().length()); + return comparison == 0 ? -1 : comparison; + } + + } + + /** + * This will take the regexes available in given organization, and evalute + * them agsint the given list of numbers, returning the first match. + * + * The list of regexes will be ordered by length to ensure the longest + * regexes matching any number in the list is returned first. + * + * In this case, organization details are required. + * + * @param numberQueries + * @param sourceOrganizationSid + * @param destOrg + * @return the longest regex matching any number in the list, null if no + * match + */ + private NumberSelectionResult findByRegex(List numberQueries, + Sid sourceOrganizationSid, Sid destOrg) { + NumberSelectionResult numberFound = new NumberSelectionResult(null, false, null); + IncomingPhoneNumberFilter.Builder filterBuilder = IncomingPhoneNumberFilter.Builder.builder(); + filterBuilder.byOrgSid(destOrg.toString()); + filterBuilder.byPureSIP(Boolean.TRUE); + List regexList = numbersDao.getIncomingPhoneNumbersRegex(filterBuilder.build()); + if (logger.isDebugEnabled()) { + logger.debug(String.format("Found %d Regex IncomingPhone numbers.", regexList.size())); + } + //order by regex length + + Set regexSet = new TreeSet(new NumberLengthComparator()); + regexSet.addAll(regexList); + if (regexList != null && regexList.size() > 0) { + NumberSelectionResult matchingRegex = findFirstMatchingRegex(numberQueries, regexSet); + if (matchingRegex.number != null) { + numberFound = matchingRegex; + } + } + + return numberFound; + } + + /** + * + * @param numberQueries the list of numbers to be matched + * @param regexSet The set of regexes to evaluate against given numbers + * @return the first regex matching any number in list, null if no match + */ + public NumberSelectionResult findFirstMatchingRegex(List numberQueries, Set regexSet + ) { + NumberSelectionResult matchedRegex = new NumberSelectionResult(null, false, null); + try { + Iterator iterator = regexSet.iterator(); + while (matchedRegex.number == null && iterator.hasNext()) { + IncomingPhoneNumber currentRegex = iterator.next(); + String phoneRegexPattern = null; + //here we perform string replacement to allow proper regex compilation + if (currentRegex.getPhoneNumber().startsWith("+")) { + //ensures leading + sign is interpreted as expected char + phoneRegexPattern = currentRegex.getPhoneNumber().replace("+", "/+"); + } else if (currentRegex.getPhoneNumber().startsWith("*")) { + //ensures leading * sign is interpreted as expected char + phoneRegexPattern = currentRegex.getPhoneNumber().replace("*", "/*"); + } else { + phoneRegexPattern = currentRegex.getPhoneNumber(); + } + Pattern p = Pattern.compile(phoneRegexPattern); + int i = 0; + //we evalute the current regex to the list of incoming numbers + //we stop as soon as a match is found + while (matchedRegex.number == null && i < numberQueries.size()) { + Matcher m = p.matcher(numberQueries.get(i)); + if (m.find()) { + //match found, exit from loops and return + matchedRegex = new NumberSelectionResult(currentRegex, false, ResultType.REGEX); + } else if (logger.isInfoEnabled()) { + String msg = String.format("Regex \"%s\" cannot be matched for phone number \"%s\"", phoneRegexPattern, numberQueries.get(i)); + logger.info(msg); + } + i = i + 1; + } + } + } catch (Exception e) { + if (logger.isDebugEnabled()) { + String msg = String.format("Exception while trying to match for a REGEX, exception: %s", e); + logger.debug(msg); + } + } + if (matchedRegex.number == null) { + logger.info("No matching phone number found, make sure your Restcomm Regex phone number is correctly defined"); + } + + return matchedRegex; + + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ResultType.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ResultType.java new file mode 100644 index 0000000000..f06a5aaa37 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ResultType.java @@ -0,0 +1,25 @@ +/* +/* + * 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; + +public enum ResultType { + REGULAR, REGEX, STAR; +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SIPOrganizationUtil.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SIPOrganizationUtil.java new file mode 100644 index 0000000000..52cee924ce --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SIPOrganizationUtil.java @@ -0,0 +1,55 @@ +/* + * 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 javax.servlet.sip.SipServletRequest; +import javax.servlet.sip.SipURI; +import org.apache.log4j.Logger; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.entities.Organization; +import org.restcomm.connect.dao.OrganizationsDao; + +public class SIPOrganizationUtil { + + private static Logger logger = Logger.getLogger(SIPOrganizationUtil.class); + + public static Sid getOrganizationSidBySipURIHost(OrganizationsDao orgDao, final SipURI sipURI) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("getOrganizationSidBySipURIHost sipURI = %s", sipURI)); + } + final String organizationDomainName = sipURI.getHost(); + Organization organization = orgDao.getOrganizationByDomainName(organizationDomainName); + if (logger.isDebugEnabled()) { + logger.debug(String.format("Org found = %s", organization)); + } + return organization == null ? null : organization.getSid(); + } + + public static Sid searchOrganizationBySIPRequest(OrganizationsDao orgDao, SipServletRequest request) { + //first try with requetURI + Sid destinationOrganizationSid = getOrganizationSidBySipURIHost(orgDao, + (SipURI) request.getRequestURI()); + if (destinationOrganizationSid == null) { + // try to get destinationOrganizationSid from toUri + destinationOrganizationSid = getOrganizationSidBySipURIHost(orgDao, (SipURI) request.getTo().getURI()); + } + return destinationOrganizationSid; + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SearchModifier.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SearchModifier.java new file mode 100644 index 0000000000..3530c8e3d1 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SearchModifier.java @@ -0,0 +1,27 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2016, 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; + +/** + * @author maria-farooq@live.com (Maria Farooq) + */ +public enum SearchModifier { + ORG_COMPLIANT + +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java similarity index 75% rename from restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreter.java rename to restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java index 69582d230a..b0913851e3 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/SmsInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java @@ -17,10 +17,69 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.interpreter; +package org.restcomm.connect.interpreter; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.redirect; -import static org.mobicents.servlet.restcomm.interpreter.rcml.Verbs.sms; +import akka.actor.Actor; +import akka.actor.ActorRef; +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.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; +import org.apache.commons.configuration.Configuration; +import org.apache.http.Header; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +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; +import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.SmsMessagesDao; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.dao.entities.SmsMessage; +import org.restcomm.connect.dao.entities.SmsMessage.Direction; +import org.restcomm.connect.dao.entities.SmsMessage.Status; +import org.restcomm.connect.email.EmailService; +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.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.ExtensionType; +import org.restcomm.connect.extension.api.IExtensionFeatureAccessRequest; +import org.restcomm.connect.extension.api.RestcommExtensionGeneric; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.http.client.Downloader; +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.rcml.Attribute; +import org.restcomm.connect.interpreter.rcml.GetNextVerb; +import org.restcomm.connect.interpreter.rcml.Parser; +import org.restcomm.connect.interpreter.rcml.ParserFailed; +import org.restcomm.connect.interpreter.rcml.Tag; +import org.restcomm.connect.interpreter.rcml.Verbs; +import org.restcomm.connect.sms.api.CreateSmsSession; +import org.restcomm.connect.sms.api.DestroySmsSession; +import org.restcomm.connect.sms.api.GetLastSmsRequest; +import org.restcomm.connect.sms.api.SmsServiceResponse; +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.telephony.api.FeatureAccessRequest; import java.io.IOException; import java.math.BigDecimal; @@ -36,64 +95,16 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.apache.commons.configuration.Configuration; -import org.apache.http.Header; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.message.BasicNameValuePair; -import org.joda.time.DateTime; -import org.mobicents.servlet.restcomm.dao.DaoManager; -import org.mobicents.servlet.restcomm.dao.NotificationsDao; -import org.mobicents.servlet.restcomm.dao.SmsMessagesDao; -import org.mobicents.servlet.restcomm.entities.Notification; -import org.mobicents.servlet.restcomm.entities.Sid; -import org.mobicents.servlet.restcomm.entities.SmsMessage; -import org.mobicents.servlet.restcomm.entities.SmsMessage.Direction; -import org.mobicents.servlet.restcomm.entities.SmsMessage.Status; -import org.mobicents.servlet.restcomm.fsm.Action; -import org.mobicents.servlet.restcomm.fsm.FiniteStateMachine; -import org.mobicents.servlet.restcomm.fsm.State; -import org.mobicents.servlet.restcomm.fsm.Transition; -import org.mobicents.servlet.restcomm.http.client.Downloader; -import org.mobicents.servlet.restcomm.http.client.DownloaderResponse; -import org.mobicents.servlet.restcomm.http.client.HttpRequestDescriptor; -import org.mobicents.servlet.restcomm.http.client.HttpResponseDescriptor; -import org.mobicents.servlet.restcomm.interpreter.rcml.Attribute; -import org.mobicents.servlet.restcomm.interpreter.rcml.GetNextVerb; -import org.mobicents.servlet.restcomm.interpreter.rcml.Parser; -import org.mobicents.servlet.restcomm.interpreter.rcml.Tag; -import org.mobicents.servlet.restcomm.patterns.Observe; -import org.mobicents.servlet.restcomm.sms.CreateSmsSession; -import org.mobicents.servlet.restcomm.sms.DestroySmsSession; -import org.mobicents.servlet.restcomm.sms.GetLastSmsRequest; -import org.mobicents.servlet.restcomm.sms.SmsServiceResponse; -import org.mobicents.servlet.restcomm.sms.SmsSessionAttribute; -import org.mobicents.servlet.restcomm.sms.SmsSessionInfo; -import org.mobicents.servlet.restcomm.sms.SmsSessionRequest; -import org.mobicents.servlet.restcomm.sms.SmsSessionResponse; - -import akka.actor.ActorRef; -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.google.i18n.phonenumbers.NumberParseException; -import com.google.i18n.phonenumbers.PhoneNumberUtil; -import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; - /** * @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); + // States for the FSM. private final State uninitialized; private final State acquiringLastSmsRequest; @@ -102,6 +113,7 @@ public final class SmsInterpreter extends UntypedActor { private final State ready; private final State redirecting; private final State creatingSmsSession; + private final State sendingEmail; private final State sendingSms; private final State waitingForSmsResponses; private final State finished; @@ -112,11 +124,14 @@ public final class SmsInterpreter extends UntypedActor { private final Map sessions; private Sid initialSessionSid; private ActorRef initialSession; + private ActorRef mailerService; private SmsSessionRequest initialSessionRequest; // HTTP Stuff. private final ActorRef downloader; // The storage engine. private final DaoManager storage; + //Email configuration + private final Configuration emailconfiguration; //Runtime configuration private final Configuration runtime; // User specific configuration. @@ -139,9 +154,10 @@ 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) { + //List of extensions for SmsInterpreter + List extensions; + + public SmsInterpreter (final SmsInterpreterParams params) { super(); final ActorRef source = self(); uninitialized = new State("uninitialized", null, null); @@ -153,67 +169,104 @@ public SmsInterpreter(final ActorRef service, final Configuration configuration, creatingSmsSession = new State("creating sms session", new CreatingSmsSession(source), null); sendingSms = new State("sending sms", new SendingSms(source), null); waitingForSmsResponses = new State("waiting for sms responses", new WaitingForSmsResponses(source), null); + sendingEmail = new State("sending Email", new SendingEmail(source), null); finished = new State("finished", new Finished(source), null); // Initialize the transitions for the FSM. final Set transitions = new HashSet(); transitions.add(new Transition(uninitialized, acquiringLastSmsRequest)); transitions.add(new Transition(acquiringLastSmsRequest, downloadingRcml)); transitions.add(new Transition(acquiringLastSmsRequest, finished)); + transitions.add(new Transition(acquiringLastSmsRequest, sendingEmail)); transitions.add(new Transition(downloadingRcml, ready)); transitions.add(new Transition(downloadingRcml, downloadingFallbackRcml)); transitions.add(new Transition(downloadingRcml, finished)); + transitions.add(new Transition(downloadingRcml, sendingEmail)); transitions.add(new Transition(downloadingFallbackRcml, ready)); transitions.add(new Transition(downloadingFallbackRcml, finished)); + transitions.add(new Transition(downloadingFallbackRcml, sendingEmail)); transitions.add(new Transition(ready, redirecting)); transitions.add(new Transition(ready, creatingSmsSession)); transitions.add(new Transition(ready, waitingForSmsResponses)); + transitions.add(new Transition(ready, sendingEmail)); transitions.add(new Transition(ready, finished)); transitions.add(new Transition(redirecting, ready)); transitions.add(new Transition(redirecting, creatingSmsSession)); transitions.add(new Transition(redirecting, finished)); + transitions.add(new Transition(redirecting, sendingEmail)); transitions.add(new Transition(redirecting, waitingForSmsResponses)); transitions.add(new Transition(creatingSmsSession, sendingSms)); transitions.add(new Transition(creatingSmsSession, waitingForSmsResponses)); + transitions.add(new Transition(creatingSmsSession, sendingEmail)); transitions.add(new Transition(creatingSmsSession, finished)); transitions.add(new Transition(sendingSms, ready)); transitions.add(new Transition(sendingSms, redirecting)); transitions.add(new Transition(sendingSms, creatingSmsSession)); transitions.add(new Transition(sendingSms, waitingForSmsResponses)); + transitions.add(new Transition(sendingSms, sendingEmail)); transitions.add(new Transition(sendingSms, finished)); transitions.add(new Transition(waitingForSmsResponses, waitingForSmsResponses)); + transitions.add(new Transition(waitingForSmsResponses, sendingEmail)); transitions.add(new Transition(waitingForSmsResponses, finished)); + transitions.add(new Transition(sendingEmail, ready)); + transitions.add(new Transition(sendingEmail, redirecting)); + transitions.add(new Transition(sendingEmail, creatingSmsSession)); + transitions.add(new Transition(sendingEmail, waitingForSmsResponses)); + transitions.add(new Transition(sendingEmail, finished)); // 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.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"); + extensions = ExtensionController.getInstance().getExtensions(ExtensionType.FeatureAccessControl); + } + + 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 UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + private ActorRef downloader () { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override - public UntypedActor create() throws Exception { + public UntypedActor create () throws Exception { return new Downloader(); } - })); + }); + return getContext().actorOf(props); + } + + ActorRef mailer (final Configuration configuration) { + final Props props = new Props(new UntypedActorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public Actor create () throws Exception { + return new EmailService(configuration); + } + }); + return getContext().actorOf(props); } - protected String format(final String number) { - if(normalizeNumber) { + protected String format (final String number) { + if (normalizeNumber) { final PhoneNumberUtil numbersUtil = PhoneNumberUtil.getInstance(); try { final PhoneNumber result = numbersUtil.parse(number, "US"); @@ -226,17 +279,17 @@ protected String format(final String number) { } } - protected void invalidVerb(final Tag verb) { + protected void invalidVerb (final Tag verb) { final ActorRef self = self(); final Notification notification = notification(WARNING_NOTIFICATION, 14110, "Invalid Verb for SMS Reply"); final NotificationsDao notifications = storage.getNotificationsDao(); notifications.addNotification(notification); // Get the next verb. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, self); } - protected Notification notification(final int log, final int error, final String message) { + protected 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); builder.setSid(sid); @@ -285,13 +338,13 @@ protected Notification notification(final int log, final int error, final String @SuppressWarnings("unchecked") @Override - public void onReceive(final Object message) throws Exception { + public void onReceive (final Object message) throws Exception { final Class klass = message.getClass(); final State state = fsm.state(); if (StartInterpreter.class.equals(klass)) { fsm.transition(message, acquiringLastSmsRequest); } else if (SmsSessionRequest.class.equals(klass)) { - customRequestHeaderMap = ((SmsSessionRequest)message).headers(); + customRequestHeaderMap = ((SmsSessionRequest) message).headers(); fsm.transition(message, downloadingRcml); } else if (DownloaderResponse.class.equals(klass)) { final DownloaderResponse response = (DownloaderResponse) message; @@ -325,12 +378,38 @@ public void onReceive(final Object message) throws Exception { } } } + } else if (ParserFailed.class.equals(klass)) { + if (logger.isInfoEnabled()) { + logger.info("ParserFailed received. Will stop the call"); + } + fsm.transition(message, finished); } else if (Tag.class.equals(klass)) { final Tag verb = (Tag) message; - if (redirect.equals(verb.name())) { + if (Verbs.redirect.equals(verb.name())) { fsm.transition(message, redirecting); - } else if (sms.equals(verb.name())) { - fsm.transition(message, creatingSmsSession); + } else if (Verbs.sms.equals(verb.name())) { + //Check if Outbound SMS is allowed + ExtensionController ec = ExtensionController.getInstance(); + final IExtensionFeatureAccessRequest far = new FeatureAccessRequest(FeatureAccessRequest.Feature.OUTBOUND_SMS, accountId); + ExtensionResponse er = ec.executePreOutboundAction(far, this.extensions); + + if (er.isAllowed()) { + fsm.transition(message, creatingSmsSession); + ec.executePostOutboundAction(far, extensions); + } else { + if (logger.isDebugEnabled()) { + final String errMsg = "Outbound SMS is not Allowed"; + logger.debug(errMsg); + } + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 11001, "Outbound SMS is now allowed"); + notifications.addNotification(notification); + fsm.transition(message, finished); + ec.executePostOutboundAction(far, extensions); + return; + } + } else if (Verbs.email.equals(verb.name())) { + fsm.transition(message, sendingEmail); } else { invalidVerb(verb); } @@ -355,6 +434,14 @@ public void onReceive(final Object message) throws Exception { } else { fsm.transition(message, finished); } + } else if (EmailResponse.class.equals(klass)) { + final EmailResponse response = (EmailResponse) message; + if (!response.succeeded()) { + logger.error( + "There was an error while sending an email :" + response.error(), + response.cause()); + } + fsm.transition(message, ready); } } @@ -383,15 +470,15 @@ protected List parameters() { } private ActorRef parser(final String xml) { - final UntypedActorContext context = getContext(); - return context.actorOf(new Props(new UntypedActorFactory() { + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { - return new Parser(xml); + return new Parser(xml, self()); } - })); + }); + return getContext().actorOf(props); } private void response(final Object message) { @@ -401,13 +488,6 @@ private void response(final Object message) { final SmsSessionResponse response = (SmsSessionResponse) message; final SmsSessionInfo info = response.info(); SmsMessage record = (SmsMessage) info.attributes().get("record"); - if (response.succeeded()) { - final DateTime now = DateTime.now(); - record = record.setDateSent(now); - record = record.setStatus(Status.SENT); - } else { - record = record.setStatus(Status.FAILED); - } final SmsMessagesDao messages = storage.getSmsMessagesDao(); messages.updateSmsMessage(record); // Notify the callback listener. @@ -425,7 +505,7 @@ record = record.setStatus(Status.FAILED); // Try to stop the interpreter. final State state = fsm.state(); if (waitingForSmsResponses.equals(state)) { - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); self.tell(stop, self); } } @@ -561,11 +641,13 @@ public void execute(final Object message) throws Exception { if ((type != null && content != null) && (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html"))) { parser = parser(content); } else { - logger.info("DownloaderResponse getContentType is null: "+response); + if(logger.isInfoEnabled()) { + logger.info("DownloaderResponse getContentType is null: "+response); + } final NotificationsDao notifications = storage.getNotificationsDao(); final Notification notification = notification(WARNING_NOTIFICATION, 12300, "Invalide content-type."); notifications.addNotification(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -573,7 +655,7 @@ public void execute(final Object message) throws Exception { final NotificationsDao notifications = storage.getNotificationsDao(); final Notification notification = notification(WARNING_NOTIFICATION, 12300, "Invalide content-type."); notifications.addNotification(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -585,7 +667,7 @@ public void execute(final Object message) throws Exception { customHttpHeaderMap.put(header.getName(), header.getValue()); } } - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -623,7 +705,7 @@ public void execute(final Object message) throws Exception { } catch (final Exception exception) { final Notification notification = notification(ERROR_NOTIFICATION, 11100, text + " is an invalid URI."); notifications.addNotification(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -634,7 +716,7 @@ public void execute(final Object message) throws Exception { downloader.tell(request, source); } else { // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -650,7 +732,7 @@ public void execute(Object message) throws Exception { // Save verb. verb = (Tag) message; // Create a new sms session to handle the verb. - service.tell(new CreateSmsSession(), source); + service.tell(new CreateSmsSession(initialSessionRequest.from(), initialSessionRequest.to(), accountId.toString(), false), source); } } @@ -678,7 +760,7 @@ public void execute(final Object message) throws Exception { + " is an invalid 'from' phone number."); notifications.addNotification(notification); service.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -716,7 +798,7 @@ public void execute(final Object message) throws Exception { final Notification notification = notification(ERROR_NOTIFICATION, 14103, body + " is an invalid SMS body."); notifications.addNotification(notification); service.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } else { @@ -735,7 +817,7 @@ public void execute(final Object message) throws Exception { + " is an invalid URI."); notifications.addNotification(notification); service.tell(new DestroySmsSession(session), source); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -786,7 +868,7 @@ public void execute(final Object message) throws Exception { final Notification notification = notification(ERROR_NOTIFICATION, 11100, action + " is an invalid URI."); notifications.addNotification(notification); - final StopInterpreter stop = StopInterpreter.instance(); + final StopInterpreter stop = new StopInterpreter(); source.tell(stop, source); return; } @@ -818,7 +900,7 @@ public void execute(final Object message) throws Exception { } } // Ask the parser for the next action to take. - final GetNextVerb next = GetNextVerb.instance(); + final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); } } @@ -845,4 +927,68 @@ public void execute(final Object message) throws Exception { context.stop(source); } } + + private final class SendingEmail extends AbstractAction { + public SendingEmail(final ActorRef source){ + super(source); + } + + @Override + public void execute( final Object message) throws Exception { + final Tag verb = (Tag)message; + // Parse "from". + String from; + Attribute attribute = verb.attribute("from"); + if (attribute != null) { + from = attribute.value(); + }else{ + Exception error = new Exception("From attribute was not defined"); + source.tell(new EmailResponse(error,error.getMessage()), source); + return; + } + + // Parse "to". + String to; + attribute = verb.attribute("to"); + if (attribute != null) { + to = attribute.value(); + }else{ + Exception error = new Exception("To attribute was not defined"); + source.tell(new EmailResponse(error,error.getMessage()), source); + return; + } + + // Parse "cc". + String cc=""; + attribute = verb.attribute("cc"); + if (attribute != null) { + cc = attribute.value(); + } + + // Parse "bcc". + String bcc=""; + attribute = verb.attribute("bcc"); + if (attribute != null) { + bcc = attribute.value(); + } + + // Parse "subject" + String subject; + attribute = verb.attribute("subject"); + if (attribute != null) { + subject = attribute.value(); + }else{ + subject="Restcomm Email Service"; + } + + // Send the email. + final Mail emailMsg = new Mail(from, to, subject, verb.text(),cc,bcc); + if (mailerService == null){ + mailerService = mailer(emailconfiguration); + } + mailerService.tell(new EmailRequest(emailMsg), self()); + } + } } + + 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/StartForking.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartForking.java new file mode 100644 index 0000000000..5f6199b565 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartForking.java @@ -0,0 +1,32 @@ +/* + * 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 org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public final class StartForking { + public StartForking() { + super(); + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartGathering.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartGathering.java similarity index 90% rename from restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartGathering.java rename to restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartGathering.java index 722392031a..fd00040027 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartGathering.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartGathering.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.interpreter; +package org.restcomm.connect.interpreter; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartInterpreter.java similarity index 90% rename from restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartInterpreter.java rename to restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartInterpreter.java index 00a6afb229..071855902d 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/mobicents/servlet/restcomm/interpreter/StartInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StartInterpreter.java @@ -17,9 +17,9 @@ * along with this program. If not, see * */ -package org.mobicents.servlet.restcomm.interpreter; +package org.restcomm.connect.interpreter; -import org.mobicents.servlet.restcomm.annotations.concurrency.Immutable; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; import akka.actor.ActorRef; diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StopInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StopInterpreter.java new file mode 100644 index 0000000000..290ed3b5c2 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/StopInterpreter.java @@ -0,0 +1,44 @@ +/* + * 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 org.restcomm.connect.commons.annotations.concurrency.Immutable; + +/** + * @author quintana.thomas@gmail.com (Thomas Quintana) + */ +@Immutable +public final class StopInterpreter { + + private final boolean liveCallModification; + + public StopInterpreter(boolean liveCallModification) { + this.liveCallModification = liveCallModification; + } + + public StopInterpreter() { + this(false); + } + + public boolean isLiveCallModification() { + return liveCallModification; + } + +} 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 new file mode 100644 index 0000000000..e3b2a69ef2 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreter.java @@ -0,0 +1,622 @@ +/* + * 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.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 org.apache.commons.configuration.Configuration; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.joda.time.DateTime; +import org.restcomm.connect.asr.AsrResponse; +import org.restcomm.connect.commons.cache.DiskCacheResponse; +import org.restcomm.connect.commons.dao.Sid; +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.telephony.CreateCallType; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.NotificationsDao; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.fax.FaxResponse; +import org.restcomm.connect.http.client.DownloaderResponse; +import org.restcomm.connect.http.client.HttpRequestDescriptor; +import org.restcomm.connect.interpreter.rcml.Attribute; +import org.restcomm.connect.interpreter.rcml.End; +import org.restcomm.connect.interpreter.rcml.GetNextVerb; +import org.restcomm.connect.interpreter.rcml.Tag; +import org.restcomm.connect.interpreter.rcml.Verbs; +import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; +import org.restcomm.connect.mscontrol.api.messages.StopMediaGroup; +import org.restcomm.connect.sms.api.SmsServiceResponse; +import org.restcomm.connect.sms.api.SmsSessionResponse; +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.Cancel; + +import org.restcomm.connect.telephony.api.DestroyCall; +import org.restcomm.connect.telephony.api.Reject; +import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; + +import javax.servlet.sip.SipServletResponse; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * @author gvagenas@telestax.com + * @author jean.deruelle@telestax.com + * @author pavel.slegr@telestax.com + */ +public final class SubVoiceInterpreter extends BaseVoiceInterpreter { + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + // States for the FSM. + private final State downloadingRcml; + private final State ready; + private final State notFound; + private final State rejecting; + private final State finished; + + // application data. + private DownloaderResponse downloaderResponse; + private ActorRef source; + private Boolean hangupOnEnd = false; + private ActorRef originalInterpreter; + + public SubVoiceInterpreter(SubVoiceInterpreterParams params) { + super(); + source = self(); + downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); + ready = new State("ready", new Ready(source), null); + notFound = new State("notFound", new NotFound(source), null); + rejecting = new State("rejecting", new Rejecting(source), null); + finished = new State("finished", new Finished(source), null); + + transitions.add(new Transition(acquiringAsrInfo, finished)); + transitions.add(new Transition(acquiringSynthesizerInfo, finished)); + transitions.add(new Transition(acquiringCallInfo, downloadingRcml)); + transitions.add(new Transition(acquiringCallInfo, finished)); + transitions.add(new Transition(downloadingRcml, ready)); + transitions.add(new Transition(downloadingRcml, notFound)); + transitions.add(new Transition(downloadingRcml, hangingUp)); + transitions.add(new Transition(downloadingRcml, finished)); + transitions.add(new Transition(ready, faxing)); + transitions.add(new Transition(ready, pausing)); + transitions.add(new Transition(ready, checkingCache)); + transitions.add(new Transition(ready, caching)); + transitions.add(new Transition(ready, synthesizing)); + transitions.add(new Transition(ready, rejecting)); + transitions.add(new Transition(ready, redirecting)); + transitions.add(new Transition(ready, processingGatherChildren)); + transitions.add(new Transition(ready, creatingRecording)); + transitions.add(new Transition(ready, creatingSmsSession)); + transitions.add(new Transition(ready, hangingUp)); + transitions.add(new Transition(ready, finished)); + transitions.add(new Transition(pausing, ready)); + transitions.add(new Transition(pausing, finished)); + transitions.add(new Transition(rejecting, finished)); + transitions.add(new Transition(faxing, ready)); + transitions.add(new Transition(faxing, finished)); + transitions.add(new Transition(caching, finished)); + transitions.add(new Transition(playing, ready)); + transitions.add(new Transition(playing, finished)); + transitions.add(new Transition(synthesizing, finished)); + transitions.add(new Transition(redirecting, ready)); + transitions.add(new Transition(redirecting, finished)); + transitions.add(new Transition(creatingRecording, finished)); + transitions.add(new Transition(finishRecording, ready)); + transitions.add(new Transition(finishRecording, finished)); + transitions.add(new Transition(processingGatherChildren, finished)); + transitions.add(new Transition(gathering, finished)); + transitions.add(new Transition(finishGathering, finished)); + transitions.add(new Transition(creatingSmsSession, finished)); + transitions.add(new Transition(sendingSms, ready)); + transitions.add(new Transition(sendingSms, finished)); + transitions.add(new Transition(hangingUp, finished)); + + // Initialize the FSM. + this.fsm = new FiniteStateMachine(uninitialized, transitions); + // Initialize the runtime stuff. + 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 = params.getSmsService(); + this.smsSessions = new HashMap(); + this.storage = params.getStorage(); +// this.synthesizer = tts(configuration.subset("speech-synthesizer")); + final Configuration runtime = configuration.subset("runtime-settings"); +// String path = runtime.getString("cache-path"); +// if (!path.endsWith("/")) { +// path = path + "/"; +// } +// path = path + accountId.toString(); +// cachePath = path; +// String uri = runtime.getString("cache-uri"); +// if (!uri.endsWith("/")) { +// uri = uri + "/"; +// } +// try { +// uri = UriUtils.resolve(new URI(uri)).toString(); +// } catch (URISyntaxException e) { +// logger.error("URISyntaxException while trying to resolve Cache URI: "+e); +// } +// uri = uri + accountId.toString(); +// this.cache = cache(path, uri); + this.downloader = downloader(); + 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) { + final Notification.Builder builder = Notification.builder(); + final Sid sid = Sid.generate(Sid.Type.NOTIFICATION); + builder.setSid(sid); + builder.setAccountSid(accountId); + builder.setCallSid(callInfo.sid()); + builder.setApiVersion(version); + builder.setLog(log); + builder.setErrorCode(error); + final String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); + StringBuilder buffer = new StringBuilder(); + buffer.append(base); + if (!base.endsWith("/")) { + buffer.append("/"); + } + buffer.append(error).append(".html"); + final URI info = URI.create(buffer.toString()); + builder.setMoreInfo(info); + builder.setMessageText(message); + final DateTime now = DateTime.now(); + builder.setMessageDate(now); + if (request != null) { + builder.setRequestUrl(request.getUri()); + builder.setRequestMethod(request.getMethod()); + builder.setRequestVariables(request.getParametersAsString()); + } + if (response != null) { + builder.setResponseHeaders(response.getHeadersAsString()); + final String type = response.getContentType(); + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + try { + builder.setResponseBody(response.getContentAsString()); + } catch (final IOException exception) { + logger.error( + "There was an error while reading the contents of the resource " + "located @ " + url.toString(), + exception); + } + } + } + buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/"); + buffer.append(accountId.toString()).append("/Notifications/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + return builder.build(); + } + + @SuppressWarnings("unchecked") + @Override + public void onReceive(final Object message) throws Exception { + final Class klass = message.getClass(); + final State state = fsm.state(); + final ActorRef sender = sender(); + + if (logger.isInfoEnabled()) { + logger.info(" ********** SubVoiceInterpreter's Current State: " + state.toString()); + logger.info(" ********** SubVoiceInterpreter's Processing Message: " + klass.getName()); + } + + if (StartInterpreter.class.equals(klass)) { + final StartInterpreter request = (StartInterpreter) message; + call = request.resource(); + originalInterpreter = sender; + fsm.transition(message, acquiringAsrInfo); + } else if (AsrResponse.class.equals(klass)) { + if (outstandingAsrRequests > 0) { + asrResponse(message); + } else { + fsm.transition(message, acquiringSynthesizerInfo); + } + } else if (SpeechSynthesizerResponse.class.equals(klass)) { + if (acquiringSynthesizerInfo.equals(state)) { + fsm.transition(message, acquiringCallInfo); + } else if (synthesizing.equals(state)) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + if (response.succeeded()) { + fsm.transition(message, caching); + } else { + fsm.transition(message, hangingUp); + } + } else if (processingGatherChildren.equals(state)) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + if (response.succeeded()) { + fsm.transition(message, processingGatherChildren); + } else { + fsm.transition(message, hangingUp); + } + } + } else if (CallResponse.class.equals(klass)) { + if (acquiringCallInfo.equals(state)) { + final CallResponse response = (CallResponse) message; + callInfo = response.get(); + fsm.transition(message, downloadingRcml); + } + } else if (DownloaderResponse.class.equals(klass)) { + downloaderResponse = (DownloaderResponse) message; + if (logger.isDebugEnabled()) { + logger.debug("response succeeded " + downloaderResponse.succeeded() + ", statusCode " + + downloaderResponse.get().getStatusCode()); + } + if (downloaderResponse.succeeded() && HttpStatus.SC_OK == downloaderResponse.get().getStatusCode()) { + fsm.transition(message, ready); + } else if (downloaderResponse.succeeded() && HttpStatus.SC_NOT_FOUND == downloaderResponse.get().getStatusCode()) { + originalInterpreter.tell(new Exception("Downloader Response Exception"), source); + fsm.transition(message, notFound); + } + } else if (DiskCacheResponse.class.equals(klass)) { + final DiskCacheResponse response = (DiskCacheResponse) message; + if (response.succeeded()) { + if (caching.equals(state) || checkingCache.equals(state)) { + if (Verbs.play.equals(verb.name()) || Verbs.say.equals(verb.name())) { + fsm.transition(message, playing); + } else if (Verbs.fax.equals(verb.name())) { + fsm.transition(message, faxing); + } + } else if (processingGatherChildren.equals(state)) { + fsm.transition(message, processingGatherChildren); + } + } else { + if (checkingCache.equals(state)) { + fsm.transition(message, synthesizing); + } else { + fsm.transition(message, hangingUp); + } + } + } else if (Tag.class.equals(klass)) { + verb = (Tag) message; + + if (Verbs.dial.equals(verb.name())) + originalInterpreter.tell(new Exception("Dial verb not supported"), source); + + if (Verbs.reject.equals(verb.name())) { + fsm.transition(message, rejecting); + } else if (Verbs.pause.equals(verb.name())) { + fsm.transition(message, pausing); + } else if (Verbs.fax.equals(verb.name())) { + fsm.transition(message, caching); + } else if (Verbs.play.equals(verb.name())) { + fsm.transition(message, caching); + } else if (Verbs.say.equals(verb.name())) { + fsm.transition(message, checkingCache); + } else if (Verbs.gather.equals(verb.name())) { + fsm.transition(message, processingGatherChildren); + } else if (Verbs.pause.equals(verb.name())) { + fsm.transition(message, pausing); + } else if (Verbs.hangup.equals(verb.name())) { + originalInterpreter.tell(message, source); + fsm.transition(message, hangingUp); + } else if (Verbs.redirect.equals(verb.name())) { + fsm.transition(message, redirecting); + } else if (Verbs.record.equals(verb.name())) { + fsm.transition(message, creatingRecording); + } else if (Verbs.sms.equals(verb.name())) { + fsm.transition(message, creatingSmsSession); + } else { + invalidVerb(verb); + } + } else if (End.class.equals(klass)) { + if (!hangupOnEnd) { + originalInterpreter.tell(message, source); + } else { + fsm.transition(message, hangingUp); + } + } else if (StartGathering.class.equals(klass)) { + fsm.transition(message, gathering); + } else if (CallStateChanged.class.equals(klass)) { + final CallStateChanged event = (CallStateChanged) message; + if (CallStateChanged.State.NO_ANSWER == event.state() || CallStateChanged.State.COMPLETED == event.state() + || CallStateChanged.State.FAILED == event.state() || CallStateChanged.State.BUSY == event.state()) { + + originalInterpreter.tell(new Cancel(), source); + } + } else if (MediaGroupResponse.class.equals(klass)) { + final MediaGroupResponse response = (MediaGroupResponse) message; + if (response.succeeded()) { + if (playingRejectionPrompt.equals(state)) { + originalInterpreter.tell(message, source); + } else if (playing.equals(state)) { + fsm.transition(message, ready); + } else if (creatingRecording.equals(state)) { + fsm.transition(message, finishRecording); + } else if (gathering.equals(state)) { + fsm.transition(message, finishGathering); + } + } else { + originalInterpreter.tell(message, source); + } + } else if (SmsServiceResponse.class.equals(klass)) { + final SmsServiceResponse response = (SmsServiceResponse) message; + if (response.succeeded()) { + if (creatingSmsSession.equals(state)) { + fsm.transition(message, sendingSms); + } + } else { + fsm.transition(message, hangingUp); + } + } else if (SmsSessionResponse.class.equals(klass)) { + smsResponse(message); + } else if (FaxResponse.class.equals(klass)) { + fsm.transition(message, ready); + } else if (StopInterpreter.class.equals(klass)) { + if (CallStateChanged.State.IN_PROGRESS == callState) { + fsm.transition(message, hangingUp); + } else { + fsm.transition(message, finished); + } + } else if (message instanceof ReceiveTimeout) { + if (pausing.equals(state)) { + fsm.transition(message, ready); + } + } + } + + @Override + List parameters() { + final List parameters = new ArrayList(); + final String callSid = callInfo.sid().toString(); + parameters.add(new BasicNameValuePair("CallSid", callSid)); + final String accountSid = accountId.toString(); + parameters.add(new BasicNameValuePair("AccountSid", accountSid)); + final String from = e164(callInfo.from()); + parameters.add(new BasicNameValuePair("From", from)); + final String to = e164(callInfo.to()); + parameters.add(new BasicNameValuePair("To", to)); + final String state = callState.toString(); + parameters.add(new BasicNameValuePair("CallStatus", state)); + parameters.add(new BasicNameValuePair("ApiVersion", version)); + final String direction = callInfo.direction(); + parameters.add(new BasicNameValuePair("Direction", direction)); + final String callerName = callInfo.fromName(); + parameters.add(new BasicNameValuePair("CallerName", callerName)); + final String forwardedFrom = callInfo.forwardedFrom(); + parameters.add(new BasicNameValuePair("ForwardedFrom", forwardedFrom)); + // Adding SIP OUT Headers and SipCallId for + // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out + if (CreateCallType.SIP == callInfo.type()) { + SipServletResponse lastResponse = callInfo.lastResponse(); + if (lastResponse != null) { + final int statusCode = lastResponse.getStatus(); + final String method = lastResponse.getMethod(); + // See https://www.twilio.com/docs/sip/receiving-sip-headers + // On a successful call setup (when a 200 OK SIP response is returned) any X-headers on the 200 OK message are + // posted to the call screening URL + if (statusCode >= 200 && statusCode < 300 && "INVITE".equalsIgnoreCase(method)) { + final String sipCallId = lastResponse.getCallId(); + parameters.add(new BasicNameValuePair("SipCallId", sipCallId)); + Iterator headerIt = lastResponse.getHeaderNames(); + while (headerIt.hasNext()) { + String headerName = headerIt.next(); + if (headerName.startsWith("X-")) { + parameters + .add(new BasicNameValuePair("SipHeader_" + headerName, lastResponse.getHeader(headerName))); + } + } + } + } + } + return parameters; + } + + private abstract class AbstractAction implements Action { + protected final ActorRef source; + + public AbstractAction(final ActorRef source) { + super(); + this.source = source; + } + } + + private final class DownloadingRcml extends AbstractAction { + public DownloadingRcml(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (CallResponse.class.equals(klass)) { + final CallResponse response = (CallResponse) message; + callInfo = response.get(); + callState = callInfo.state(); + // Ask the downloader to get us the application that will be executed. + final List parameters = parameters(); + request = new HttpRequestDescriptor(url, method, parameters); + downloader.tell(request, source); + } + } + } + + private final class Ready extends AbstractAction { + public Ready(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + if (parser == null) { + response = downloaderResponse.get(); + + final String type = response.getContentType(); + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + parser = parser(response.getContentAsString()); + } else if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { + parser = parser("" + request.getUri() + ""); + } else if (type.contains("text/plain")) { + parser = parser("" + response.getContentAsString() + ""); + } else { + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); + } + } + + private final class NotFound extends AbstractAction { + public NotFound(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final DownloaderResponse response = (DownloaderResponse) message; + if (logger.isDebugEnabled()) { + logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); + } + final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " + + response.get().getURI()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + // Hang up the call. + call.tell(new org.restcomm.connect.telephony.api.NotFound(), source); + } + } + + private final class Rejecting extends AbstractAction { + public Rejecting(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + String reason = "rejected"; + Attribute attribute = verb.attribute("reason"); + if (attribute != null) { + reason = attribute.value(); + if (reason != null && !reason.isEmpty()) { + if ("rejected".equalsIgnoreCase(reason)) { + reason = "rejected"; + } else if ("busy".equalsIgnoreCase(reason)) { + reason = "busy"; + } else { + reason = "rejected"; + } + } else { + reason = "rejected"; + } + } + // Reject the call. + call.tell(new Reject(reason), source); + } + } + + private final class Finished extends AbstractAction { + + public Finished(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + + if (CallStateChanged.class.equals(klass)) { + final CallStateChanged event = (CallStateChanged) message; + callState = event.state(); + if (callRecord != null) { + callRecord = callRecord.setStatus(callState.toString()); + final DateTime end = DateTime.now(); + callRecord = callRecord.setEndTime(end); + final int seconds = (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000; + callRecord = callRecord.setDuration(seconds); + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + records.updateCallDetailRecord(callRecord); + } + callback(); + } + + // Stop the media group(s). + if (call != null) { + final StopMediaGroup stop = new StopMediaGroup(); + call.tell(stop, source); + } + + // Destroy the Call(s). + callManager.tell(new DestroyCall(call), source); + + // Stop the dependencies. + final UntypedActorContext context = getContext(); + if (mailerNotify != null) + context.stop(mailerNotify); + context.stop(downloader); + context.stop(getAsrService()); + context.stop(getFaxService()); + context.stop(getCache()); + context.stop(getSynthesizer()); + + // Stop the interpreter. + postCleanup(); + } + } +} 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 new file mode 100644 index 0000000000..8897a53d48 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -0,0 +1,3574 @@ +/* + * 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.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; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.message.BasicNameValuePair; +import org.joda.time.DateTime; +import org.joda.time.Interval; +import org.restcomm.connect.asr.AsrResponse; +import org.restcomm.connect.commons.cache.DiskCacheResponse; +import org.restcomm.connect.commons.dao.Sid; +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.fsm.TransitionFailedException; +import org.restcomm.connect.commons.fsm.TransitionNotFoundException; +import org.restcomm.connect.commons.fsm.TransitionRollbackException; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.StopObserving; +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.NotificationsDao; +import org.restcomm.connect.dao.entities.CallDetailRecord; +import org.restcomm.connect.dao.entities.MediaAttributes; +import org.restcomm.connect.dao.entities.Notification; +import org.restcomm.connect.email.api.EmailResponse; +import org.restcomm.connect.extension.api.ExtensionResponse; +import org.restcomm.connect.extension.api.IExtensionFeatureAccessRequest; +import org.restcomm.connect.extension.controller.ExtensionController; +import org.restcomm.connect.fax.FaxResponse; +import org.restcomm.connect.http.client.DownloaderResponse; +import org.restcomm.connect.http.client.HttpRequestDescriptor; +import org.restcomm.connect.interpreter.rcml.Attribute; +import org.restcomm.connect.interpreter.rcml.End; +import org.restcomm.connect.interpreter.rcml.GetNextVerb; +import org.restcomm.connect.interpreter.rcml.Nouns; +import org.restcomm.connect.interpreter.rcml.ParserFailed; +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; +import org.restcomm.connect.mscontrol.api.messages.Mute; +import org.restcomm.connect.mscontrol.api.messages.Play; +import org.restcomm.connect.mscontrol.api.messages.StartRecording; +import org.restcomm.connect.mscontrol.api.messages.StopMediaGroup; +import org.restcomm.connect.mscontrol.api.messages.Unmute; +import org.restcomm.connect.sms.api.SmsServiceResponse; +import org.restcomm.connect.sms.api.SmsSessionResponse; +import org.restcomm.connect.telephony.api.AddParticipant; +import org.restcomm.connect.telephony.api.Answer; +import org.restcomm.connect.telephony.api.BridgeManagerResponse; +import org.restcomm.connect.telephony.api.BridgeStateChanged; +import org.restcomm.connect.telephony.api.CallFail; +import org.restcomm.connect.telephony.api.CallHoldStateChange; +import org.restcomm.connect.telephony.api.CallInfo; +import org.restcomm.connect.telephony.api.CallManagerResponse; +import org.restcomm.connect.telephony.api.CallResponse; +import org.restcomm.connect.telephony.api.CallStateChanged; +import org.restcomm.connect.telephony.api.Cancel; +import org.restcomm.connect.telephony.api.ConferenceCenterResponse; +import org.restcomm.connect.telephony.api.ConferenceInfo; +import org.restcomm.connect.telephony.api.ConferenceModeratorPresent; +import org.restcomm.connect.telephony.api.ConferenceResponse; +import org.restcomm.connect.telephony.api.ConferenceStateChanged; +import org.restcomm.connect.telephony.api.CreateBridge; +import org.restcomm.connect.telephony.api.CreateCall; +import org.restcomm.connect.telephony.api.CreateConference; +import org.restcomm.connect.telephony.api.DestroyCall; +import org.restcomm.connect.telephony.api.DestroyConference; +import org.restcomm.connect.telephony.api.Dial; +import org.restcomm.connect.telephony.api.FeatureAccessRequest; +import org.restcomm.connect.telephony.api.GetCallInfo; +import org.restcomm.connect.telephony.api.GetConferenceInfo; +import org.restcomm.connect.telephony.api.GetRelatedCall; +import org.restcomm.connect.telephony.api.Hangup; +import org.restcomm.connect.telephony.api.JoinCalls; +import org.restcomm.connect.telephony.api.Reject; +import org.restcomm.connect.telephony.api.RemoveParticipant; +import org.restcomm.connect.telephony.api.StartBridge; +import org.restcomm.connect.telephony.api.StopBridge; +import org.restcomm.connect.telephony.api.StopConference; +import org.restcomm.connect.telephony.api.StopWaiting; +import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import javax.servlet.sip.SipServletMessage; +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; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +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; + +import static akka.pattern.Patterns.ask; + +/** + * @author thomas.quintana@telestax.com (Thomas Quintana) + * @author jean.deruelle@telestax.com + * @author gvagenas@telestax.com + * @author amit.bhayani@telestax.com (Amit Bhayani) + * @author pavel.slegr@telestax.com + * @author maria.farooq@telestax.com + */ +public class VoiceInterpreter extends BaseVoiceInterpreter { + // Logger. + private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); + + // States for the FSM. + private final State startDialing; + private final State processingDialChildren; + private final State acquiringOutboundCallInfo; + private final State forking; + // private final State joiningCalls; + private final State creatingBridge; + private final State initializingBridge; + private final State bridging; + private final State bridged; + private final State finishDialing; + private final State acquiringConferenceInfo; + private final State joiningConference; + private final State conferencing; + private final State finishConferencing; + private final State downloadingRcml; + private final State downloadingFallbackRcml; + private final State initializingCall; + // private final State initializedCall; + private final State ready; + private final State notFound; + private final State rejecting; + private final State finished; + + // FSM. + // The conference Ceneter. + private final ActorRef conferenceCenter; + + // State for outbound calls. + private boolean isForking; + private List dialBranches; + private List dialChildren; + private Map dialChildrenWithAttributes; + + // The conferencing stuff + private int maxParticipantLimit = 40; + private ActorRef conference; + private Sid conferenceSid; + private ConferenceInfo conferenceInfo; + private ConferenceStateChanged.State conferenceState; + private boolean muteCall; + private boolean startConferenceOnEnter = true; + private boolean endConferenceOnExit = false; + private boolean confModeratorPresent = false; + private ActorRef confSubVoiceInterpreter; + private Attribute dialRecordAttribute; + private boolean dialActionExecuted = false; + private ActorRef sender; + private boolean liveCallModification = false; + private boolean recordingCall = true; + protected boolean isParserFailed = false; + protected boolean playWaitUrlPending = false; + Tag conferenceVerb; + List conferenceWaitUris; + private boolean playMusicForConference = false; + private MediaAttributes mediaAttributes; + //Used for system apps, such as when WebRTC client is dialing out. + //The rcml will be used instead of download the RCML + private String rcml; + + // Call bridging + private final ActorRef bridgeManager; + private ActorRef bridge; + private boolean beep; + + private boolean enable200OkDelay; + + // IMS authentication + private boolean asImsUa; + private String imsUaLogin; + private String imsUaPassword; + private String forwardedFrom; + private Attribute action; + + private String conferenceNameWithAccountAndFriendlyName; + private Sid callSid; + + // Controls if VI will wait MS response to move to the next verb + protected boolean msResponsePending; + + private boolean callWaitingForAnswer = false; + + private Tag callWaitingForAnswerPendingTag; + + private long timeout; + + public VoiceInterpreter(VoiceInterpreterParams params) { + super(); + final ActorRef source = self(); + downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); + downloadingFallbackRcml = new State("downloading fallback rcml", new DownloadingFallbackRcml(source), null); + initializingCall = new State("initializing call", new InitializingCall(source), null); + // initializedCall = new State("initialized call", new InitializedCall(source), new PostInitializedCall(source)); + ready = new State("ready", new Ready(source), null); + notFound = new State("notFound", new NotFound(source), null); + rejecting = new State("rejecting", new Rejecting(source), null); + startDialing = new State("start dialing", new StartDialing(source), null); + processingDialChildren = new State("processing dial children", new ProcessingDialChildren(source), null); + acquiringOutboundCallInfo = new State("acquiring outbound call info", new AcquiringOutboundCallInfo(source), null); + forking = new State("forking", new Forking(source), null); + // joiningCalls = new State("joining calls", new JoiningCalls(source), null); + this.creatingBridge = new State("creating bridge", new CreatingBridge(source), null); + this.initializingBridge = new State("initializing bridge", new InitializingBridge(source), null); + this.bridging = new State("bridging", new Bridging(source), null); + bridged = new State("bridged", new Bridged(source), null); + finishDialing = new State("finish dialing", new FinishDialing(source), null); + acquiringConferenceInfo = new State("acquiring conference info", new AcquiringConferenceInfo(source), null); + joiningConference = new State("joining conference", new JoiningConference(source), null); + conferencing = new State("conferencing", new Conferencing(source), null); + finishConferencing = new State("finish conferencing", new FinishConferencing(source), null); + finished = new State("finished", new Finished(source), null); + /* + * dialing = new State("dialing", null, null); bridging = new State("bridging", null, null); conferencing = new + * State("conferencing", null, null); + */ + transitions.add(new Transition(acquiringAsrInfo, finished)); + transitions.add(new Transition(acquiringSynthesizerInfo, finished)); + transitions.add(new Transition(acquiringCallInfo, initializingCall)); + transitions.add(new Transition(acquiringCallInfo, downloadingRcml)); + transitions.add(new Transition(acquiringCallInfo, finished)); + transitions.add(new Transition(acquiringCallInfo, ready)); + transitions.add(new Transition(initializingCall, downloadingRcml)); + transitions.add(new Transition(initializingCall, ready)); + transitions.add(new Transition(initializingCall, finishDialing)); + transitions.add(new Transition(initializingCall, hangingUp)); + transitions.add(new Transition(initializingCall, finished)); + transitions.add(new Transition(downloadingRcml, ready)); + transitions.add(new Transition(downloadingRcml, notFound)); + transitions.add(new Transition(downloadingRcml, downloadingFallbackRcml)); + transitions.add(new Transition(downloadingRcml, hangingUp)); + transitions.add(new Transition(downloadingRcml, finished)); + transitions.add(new Transition(downloadingFallbackRcml, ready)); + transitions.add(new Transition(downloadingFallbackRcml, hangingUp)); + transitions.add(new Transition(downloadingFallbackRcml, finished)); + transitions.add(new Transition(downloadingFallbackRcml, notFound)); + transitions.add(new Transition(ready, initializingCall)); + transitions.add(new Transition(ready, faxing)); + transitions.add(new Transition(ready, sendingEmail)); + transitions.add(new Transition(ready, pausing)); + transitions.add(new Transition(ready, checkingCache)); + transitions.add(new Transition(ready, caching)); + transitions.add(new Transition(ready, synthesizing)); + transitions.add(new Transition(ready, rejecting)); + transitions.add(new Transition(ready, redirecting)); + transitions.add(new Transition(ready, processingGatherChildren)); + transitions.add(new Transition(ready, creatingRecording)); + transitions.add(new Transition(ready, creatingSmsSession)); + transitions.add(new Transition(ready, startDialing)); + transitions.add(new Transition(ready, hangingUp)); + transitions.add(new Transition(ready, finished)); + transitions.add(new Transition(pausing, ready)); + transitions.add(new Transition(pausing, finished)); + transitions.add(new Transition(rejecting, finished)); + transitions.add(new Transition(faxing, ready)); + transitions.add(new Transition(faxing, finished)); + transitions.add(new Transition(sendingEmail, ready)); + transitions.add(new Transition(sendingEmail, finished)); + transitions.add(new Transition(sendingEmail, finishDialing)); + transitions.add(new Transition(checkingCache, caching)); + transitions.add(new Transition(checkingCache, conferencing)); + transitions.add(new Transition(caching, finished)); + transitions.add(new Transition(caching, conferencing)); + transitions.add(new Transition(caching, finishConferencing)); + transitions.add(new Transition(playing, ready)); + transitions.add(new Transition(playing, finishConferencing)); + transitions.add(new Transition(playing, finished)); + transitions.add(new Transition(synthesizing, finished)); + transitions.add(new Transition(redirecting, ready)); + transitions.add(new Transition(redirecting, finished)); + transitions.add(new Transition(creatingRecording, finished)); + transitions.add(new Transition(finishRecording, ready)); + transitions.add(new Transition(finishRecording, finished)); + transitions.add(new Transition(processingGatherChildren, finished)); + transitions.add(new Transition(gathering, finished)); + transitions.add(new Transition(finishGathering, ready)); + transitions.add(new Transition(finishGathering, finishGathering)); + transitions.add(new Transition(finishGathering, finished)); + transitions.add(new Transition(continuousGathering, ready)); + transitions.add(new Transition(continuousGathering, finishGathering)); + transitions.add(new Transition(continuousGathering, finished)); + transitions.add(new Transition(creatingSmsSession, finished)); + transitions.add(new Transition(sendingSms, ready)); + transitions.add(new Transition(sendingSms, startDialing)); + transitions.add(new Transition(sendingSms, finished)); + transitions.add(new Transition(startDialing, processingDialChildren)); + transitions.add(new Transition(startDialing, acquiringConferenceInfo)); + transitions.add(new Transition(startDialing, faxing)); + transitions.add(new Transition(startDialing, sendingEmail)); + transitions.add(new Transition(startDialing, pausing)); + transitions.add(new Transition(startDialing, checkingCache)); + transitions.add(new Transition(startDialing, caching)); + transitions.add(new Transition(startDialing, synthesizing)); + transitions.add(new Transition(startDialing, redirecting)); + transitions.add(new Transition(startDialing, processingGatherChildren)); + transitions.add(new Transition(startDialing, creatingRecording)); + transitions.add(new Transition(startDialing, creatingSmsSession)); + transitions.add(new Transition(startDialing, startDialing)); + transitions.add(new Transition(startDialing, hangingUp)); + transitions.add(new Transition(startDialing, finished)); + transitions.add(new Transition(processingDialChildren, processingDialChildren)); + transitions.add(new Transition(processingDialChildren, forking)); + transitions.add(new Transition(processingDialChildren, startDialing)); + transitions.add(new Transition(processingDialChildren, checkingCache)); + transitions.add(new Transition(processingDialChildren, sendingEmail)); + transitions.add(new Transition(processingDialChildren, faxing)); + transitions.add(new Transition(processingDialChildren, sendingSms)); + transitions.add(new Transition(processingDialChildren, playing)); + transitions.add(new Transition(processingDialChildren, pausing)); + transitions.add(new Transition(processingDialChildren, ready)); + transitions.add(new Transition(processingDialChildren, hangingUp)); + transitions.add(new Transition(processingDialChildren, finished)); + transitions.add(new Transition(forking, acquiringOutboundCallInfo)); + transitions.add(new Transition(forking, finishDialing)); + transitions.add(new Transition(forking, hangingUp)); + transitions.add(new Transition(forking, finished)); + transitions.add(new Transition(forking, ready)); + transitions.add(new Transition(forking, checkingCache)); + transitions.add(new Transition(forking, caching)); + transitions.add(new Transition(forking, faxing)); + transitions.add(new Transition(forking, sendingEmail)); + transitions.add(new Transition(forking, pausing)); + transitions.add(new Transition(forking, synthesizing)); + transitions.add(new Transition(forking, redirecting)); + transitions.add(new Transition(forking, processingGatherChildren)); + transitions.add(new Transition(forking, creatingRecording)); + transitions.add(new Transition(forking, creatingSmsSession)); + // transitions.add(new Transition(acquiringOutboundCallInfo, joiningCalls)); + transitions.add(new Transition(acquiringOutboundCallInfo, hangingUp)); + transitions.add(new Transition(acquiringOutboundCallInfo, finished)); + transitions.add(new Transition(acquiringOutboundCallInfo, creatingBridge)); + transitions.add(new Transition(creatingBridge, initializingBridge)); + transitions.add(new Transition(creatingBridge, finishDialing)); + transitions.add(new Transition(initializingBridge, bridging)); + transitions.add(new Transition(initializingBridge, hangingUp)); + transitions.add(new Transition(initializingBridge, finished)); + transitions.add(new Transition(bridging, bridged)); + transitions.add(new Transition(bridging, finishDialing)); + transitions.add(new Transition(bridged, finishDialing)); + transitions.add(new Transition(bridged, finished)); + transitions.add(new Transition(finishDialing, ready)); + transitions.add(new Transition(finishDialing, faxing)); + transitions.add(new Transition(finishDialing, sendingEmail)); + transitions.add(new Transition(finishDialing, pausing)); + transitions.add(new Transition(finishDialing, checkingCache)); + transitions.add(new Transition(finishDialing, caching)); + transitions.add(new Transition(finishDialing, synthesizing)); + transitions.add(new Transition(finishDialing, redirecting)); + transitions.add(new Transition(finishDialing, processingGatherChildren)); + transitions.add(new Transition(finishDialing, creatingRecording)); + transitions.add(new Transition(finishDialing, creatingSmsSession)); + transitions.add(new Transition(finishDialing, startDialing)); + transitions.add(new Transition(finishDialing, hangingUp)); + transitions.add(new Transition(finishDialing, finished)); + transitions.add(new Transition(finishDialing, initializingCall)); + transitions.add(new Transition(acquiringConferenceInfo, joiningConference)); + transitions.add(new Transition(acquiringConferenceInfo, hangingUp)); + transitions.add(new Transition(acquiringConferenceInfo, finished)); + transitions.add(new Transition(joiningConference, conferencing)); + transitions.add(new Transition(joiningConference, acquiringConferenceInfo)); + transitions.add(new Transition(joiningConference, hangingUp)); + transitions.add(new Transition(joiningConference, finished)); + transitions.add(new Transition(conferencing, finishConferencing)); + transitions.add(new Transition(conferencing, hangingUp)); + transitions.add(new Transition(conferencing, finished)); + transitions.add(new Transition(conferencing, checkingCache)); + transitions.add(new Transition(conferencing, caching)); + transitions.add(new Transition(conferencing, playing)); + transitions.add(new Transition(conferencing, startDialing)); + transitions.add(new Transition(conferencing, creatingSmsSession)); + transitions.add(new Transition(conferencing, sendingEmail)); + transitions.add(new Transition(finishConferencing, ready)); + transitions.add(new Transition(finishConferencing, faxing)); + transitions.add(new Transition(finishConferencing, sendingEmail)); + transitions.add(new Transition(finishConferencing, pausing)); + transitions.add(new Transition(finishConferencing, checkingCache)); + transitions.add(new Transition(finishConferencing, caching)); + transitions.add(new Transition(finishConferencing, synthesizing)); + transitions.add(new Transition(finishConferencing, redirecting)); + transitions.add(new Transition(finishConferencing, processingGatherChildren)); + transitions.add(new Transition(finishConferencing, creatingRecording)); + transitions.add(new Transition(finishConferencing, creatingSmsSession)); + transitions.add(new Transition(finishConferencing, startDialing)); + transitions.add(new Transition(finishConferencing, hangingUp)); + transitions.add(new Transition(finishConferencing, finished)); + transitions.add(new Transition(hangingUp, finished)); + transitions.add(new Transition(hangingUp, finishConferencing)); + transitions.add(new Transition(hangingUp, finishDialing)); + transitions.add(new Transition(hangingUp, ready)); + transitions.add(new Transition(uninitialized, finished)); + transitions.add(new Transition(notFound, finished)); + // Initialize the FSM. + this.fsm = new FiniteStateMachine(uninitialized, transitions); + // Initialize the runtime stuff. + 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 = 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 = params.getMonitoring(); + this.rcml = params.getRcml(); + this.asImsUa = params.isAsImsUa(); + this.imsUaLogin = params.getImsUaLogin(); + this.imsUaPassword = params.getImsUaPassword(); + this.timeout = params.getTimeout(); + this.msResponsePending = false; + this.mediaAttributes = new MediaAttributes(); + } + + public static Props props(final VoiceInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new VoiceInterpreter(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); + builder.setSid(sid); + builder.setAccountSid(accountId); + builder.setCallSid(callInfo.sid()); + builder.setApiVersion(version); + builder.setLog(log); + builder.setErrorCode(error); + String base = configuration.subset("runtime-settings").getString("error-dictionary-uri"); + try { + base = UriUtils.resolve(new URI(base)).toString(); + } catch (URISyntaxException e) { + logger.error("URISyntaxException when trying to resolve Error-Dictionary URI: " + e); + } + StringBuilder buffer = new StringBuilder(); + buffer.append(base); + if (!base.endsWith("/")) { + buffer.append("/"); + } + buffer.append(error).append(".html"); + final URI info = URI.create(buffer.toString()); + builder.setMoreInfo(info); + builder.setMessageText(message); + final DateTime now = DateTime.now(); + builder.setMessageDate(now); + if (request != null) { + builder.setRequestUrl(request.getUri()); + builder.setRequestMethod(request.getMethod()); + builder.setRequestVariables(request.getParametersAsString()); + } + if (response != null) { + builder.setResponseHeaders(response.getHeadersAsString()); + final String type = response.getContentType(); + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + try { + builder.setResponseBody(response.getContentAsString()); + } catch (final IOException exception) { + logger.error( + "There was an error while reading the contents of the resource " + "located @ " + url.toString(), + exception); + } + } + } + buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/"); + buffer.append(accountId.toString()).append("/Notifications/"); + buffer.append(sid.toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + return builder.build(); + } + + @SuppressWarnings("unchecked") + @Override + public void onReceive(final Object message) throws Exception { + final Class klass = message.getClass(); + final State state = fsm.state(); + sender = sender(); + ActorRef self = self(); + + if (logger.isInfoEnabled()) { + logger.info(" ********** VoiceInterpreter's " + self().path() + " Current State: " + state.toString() + "\n" + + ", Processing Message: " + klass.getName() + " Sender is: "+sender.path()); + } + + if (StartInterpreter.class.equals(klass)) { + final StartInterpreter request = (StartInterpreter) message; + call = request.resource(); + fsm.transition(message, acquiringAsrInfo); + } else if (AsrResponse.class.equals(klass)) { + onAsrResponse(message); + } else if (SpeechSynthesizerResponse.class.equals(klass)) { + onSpeechSynthesizerResponse(message); + } else if (CallResponse.class.equals(klass)) { + onCallResponse(message, state); + } else if (CallStateChanged.class.equals(klass)) { + onCallStateChanged(message, sender); + } else if (CallManagerResponse.class.equals(klass)) { + onCallManagerResponse(message); + } else if (StartForking.class.equals(klass)) { + fsm.transition(message, processingDialChildren); + } else if (ConferenceCenterResponse.class.equals(klass)) { + onConferenceCenterResponse(message); + } else if (Fork.class.equals(klass)) { + onForkMessage(message); + } else if (ConferenceResponse.class.equals(klass)) { + onConferenceResponse(message); + } else if (ConferenceStateChanged.class.equals(klass)) { + onConferenceStateChanged(message); + } else if (DownloaderResponse.class.equals(klass)) { + onDownloaderResponse(message, state); + } else if (DiskCacheResponse.class.equals(klass)) { + onDiskCacheResponse(message); + } else if (ParserFailed.class.equals(klass)) { + onParserFailed(message); + } else if (Tag.class.equals(klass)) { + onTagMessage(message); + } else if (End.class.equals(klass)) { + onEndMessage(message); + } else if (StartGathering.class.equals(klass)) { + fsm.transition(message, gathering); + } else if (MediaGroupResponse.class.equals(klass)) { + onMediaGroupResponse(message); + } else if (SmsServiceResponse.class.equals(klass)) { + onSmsServiceResponse(message); + } else if (SmsSessionResponse.class.equals(klass)) { + smsResponse(message); + } else if (FaxResponse.class.equals(klass)) { + fsm.transition(message, ready); + } else if (EmailResponse.class.equals(klass)) { + onEmailResponse(message); + } else if (StopInterpreter.class.equals(klass)) { + onStopInterpreter(message); + } else if (message instanceof ReceiveTimeout) { + onReceiveTimeout(message); + } else if (BridgeManagerResponse.class.equals(klass)) { + onBridgeManagerResponse((BridgeManagerResponse) message, self, sender); + } else if (BridgeStateChanged.class.equals(klass)) { + onBridgeStateChanged((BridgeStateChanged) message, self, sender); + } else if (GetRelatedCall.class.equals(klass)) { + onGetRelatedCall((GetRelatedCall) message, self, sender); + } else if (JoinComplete.class.equals(klass)) { + onJoinComplete((JoinComplete)message); + } else if (CallHoldStateChange.class.equals(klass)) { + onCallHoldStateChange((CallHoldStateChange)message, sender); + } + } + + private void onJoinComplete(JoinComplete message) throws TransitionNotFoundException, TransitionFailedException, TransitionRollbackException { + if (logger.isInfoEnabled()) { + logger.info("JoinComplete received, sender: " + sender().path() + ", VI state: " + fsm.state()); + } + if (is(joiningConference)) { + fsm.transition(message, conferencing); + } + } + + private void onAsrResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (outstandingAsrRequests > 0) { + asrResponse(message); + } else { + fsm.transition(message, acquiringSynthesizerInfo); + } + } + + private void onForkMessage(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (is(processingDialChildren)) { + fsm.transition(message, forking); + } + } + + private void onConferenceCenterResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (is(startDialing) || is(joiningConference)) { + ConferenceCenterResponse ccReponse = (ConferenceCenterResponse)message; + if(ccReponse.succeeded()){ + fsm.transition(message, acquiringConferenceInfo); + }else{ + fsm.transition(message, hangingUp); + } + } + } + + private void onConferenceResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final ConferenceResponse response = (ConferenceResponse) message; + final Class klass = ((ConferenceResponse)message).get().getClass(); + if (logger.isDebugEnabled()) { + logger.debug("New ConferenceResponse received with message: "+klass.getName()); + } + if (Left.class.equals(klass)) { + Left left = (Left) ((ConferenceResponse)message).get(); + ActorRef leftCall = left.get(); + if (leftCall.equals(call) && conference != null) { + if(conferenceInfo.globalParticipants() !=0 ){ + String path = configuration.subset("runtime-settings").getString("prompts-uri"); + if (!path.endsWith("/")) { + path += "/"; + } + String exitAudio = configuration.subset("runtime-settings").getString("conference-exit-audio"); + path += exitAudio == null || exitAudio.equals("") ? "alert.wav" : exitAudio; + URI uri = null; + try { + uri = UriUtils.resolve(new URI(path)); + } catch (final Exception exception) { + final Notification notification = notification(ERROR_NOTIFICATION, 12400, exception.getMessage()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + self().tell(stop, self()); + return; + } + if (logger.isInfoEnabled()) { + logger.info("going to play conference-exit-audio beep"); + } + final Play play = new Play(uri, 1); + conference.tell(play, self()); + } + + if (endConferenceOnExit) { + // Stop the conference if endConferenceOnExit is true + final StopConference stop = new StopConference(); + conference.tell(stop, self()); + } + + Attribute attribute = null; + if (verb != null) { + attribute = verb.attribute(GatherAttributes.ATTRIBUTE_ACTION); + } + + if (attribute == null) { + if (logger.isInfoEnabled()) { + logger.info("Attribute is null, will ask for the next verb from parser"); + } + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + } else { + if (logger.isInfoEnabled()) { + logger.info("Dial Action is set, executing Dial Action"); + } + executeDialAction(message, sender); + } + conference.tell(new StopObserving(self()), null); + } + } else if (ConferenceInfo.class.equals(klass)) { + conferenceInfo = response.get(); + if (logger.isInfoEnabled()) { + logger.info("VoiceInterpreter received ConferenceResponse from Conference: " + conferenceInfo.name() + ", path: " + sender().path() + ", current confernce size: " + conferenceInfo.globalParticipants() + ", VI state: " + fsm.state()); + } + if (is(acquiringConferenceInfo)) { + fsm.transition(message, joiningConference); + } + } + } + + private void onConferenceStateChanged(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final ConferenceStateChanged event = (ConferenceStateChanged) message; + if(logger.isInfoEnabled()) { + logger.info("onConferenceStateChanged: "+event.state()); + } + switch (event.state()) { + case RUNNING_MODERATOR_PRESENT: + conferenceState = event.state(); + conferenceStateModeratorPresent(message); + break; + case COMPLETED: + conferenceState = event.state(); + //Move to finishConferencing only if we are not in Finished state already + //There are cases were we have already finished conferencing, for example when there is + //conference timeout + if (!is(finished)) + fsm.transition(message, finishConferencing); + break; + case STOPPING: + conferenceState = event.state(); + if(is(joiningConference)){ + if(logger.isInfoEnabled()) { + logger.info("We tried to join a stopping conference. Will ask Conference Center to create a new conference for us."); + } + final CreateConference create = new CreateConference(conferenceNameWithAccountAndFriendlyName, callSid); + conferenceCenter.tell(create, self()); + } + default: + break; + } + + // !!IMPORTANT!! + // Do not listen to COMPLETED nor FAILED conference state changes + // When a conference stops it will ask all its calls to Leave + // Then the call state will change and the voice interpreter will take proper action then + } + + private void onParserFailed(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if(logger.isInfoEnabled()) { + logger.info("ParserFailed received. Will stop the call"); + } + isParserFailed = true; + fsm.transition(message, hangingUp); + } + + private void onStopInterpreter(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + this.liveCallModification = ((StopInterpreter) message).isLiveCallModification(); + if (logger.isInfoEnabled()) { + String msg = String.format("Got StopInterpreter, liveCallModification %s, CallState %s", liveCallModification, callState); + logger.info(msg); + } + if (CallStateChanged.State.IN_PROGRESS.equals(callState) && !liveCallModification) { + fsm.transition(message, hangingUp); + } else { + fsm.transition(message, finished); + } + } + + private void onReceiveTimeout(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (logger.isInfoEnabled()) { + logger.info("Timeout received"); + } + if (is(pausing)) { + fsm.transition(message, ready); + } else if (is(conferencing)) { + fsm.transition(message, finishConferencing); + } else if (is(forking)) { + fsm.transition(message, finishDialing); + } else if (is(bridged)) { + fsm.transition(message, finishDialing); + } else if (is(bridging)) { + fsm.transition(message, finishDialing); + } else if (is(playing) || is(initializingCall)) { + fsm.transition(message, finished); + } + } + + private void onEmailResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final EmailResponse response = (EmailResponse) message; + if (!response.succeeded()) { + logger.error( + "There was an error while sending an email :" + response.error(), + response.cause()); + return; + } + fsm.transition(message, ready); + } + + private void onSmsServiceResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final SmsServiceResponse response = (SmsServiceResponse) message; + if (response.succeeded()) { + if (is(creatingSmsSession)) { + fsm.transition(message, sendingSms); + } + } else { + fsm.transition(message, hangingUp); + } + } + + private void onMediaGroupResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final MediaGroupResponse response = (MediaGroupResponse) message; + if(logger.isInfoEnabled()) { + logger.info("MediaGroupResponse, succeeded: " + response.succeeded() + " " + response.cause()); + } + if (response.succeeded()) { + if (is(playingRejectionPrompt)) { + fsm.transition(message, hangingUp); + } else if (is(playing)) { + fsm.transition(message, ready); + } else if (is(creatingRecording)) { + if (logger.isInfoEnabled()) { + logger.info("Will move to finishRecording because of MediaGroupResponse"); + } + 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) && !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 (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 + collectedDigits.append(dtmfResponse.get()); + // Collected digits == requested num of digits the complete the collect digits + //Zendesk_34592: if collected digits smaller than numDigits in gather verb + // when timeout on gather occur, garthering cannot move to finishGathering + // If collected digits have finish on key at the end then complete the collect digits + if (collectedDigits.toString().endsWith(finishOnKey)) { + dtmfReceived = true; + fsm.transition(message, finishGathering); + } else { + if (numberOfDigits != Short.MAX_VALUE) { + if (collectedDigits.length() == numberOfDigits) { + dtmfReceived = true; + fsm.transition(message, finishGathering); + } else { + dtmfReceived = false; + return; + } + } else { + dtmfReceived = false; + return; + } + } + } else { + collectedDigits.append(((CollectedResult)data).getResult()); + fsm.transition(message, finishGathering); + } + } + } else if (is(bridging)) { + // Finally proceed with call bridging + if (logger.isInfoEnabled()) { + String msg = String.format("About to join calls, inbound call %s, outbound call %s", call, outboundCall); + logger.info(msg); + } + final JoinCalls bridgeCalls = new JoinCalls(call, outboundCall); + bridge.tell(bridgeCalls, self()); + } else if (msResponsePending) { + // Move to next verb once media server completed Play + msResponsePending = false; + final boolean noBranches = dialBranches == null || dialBranches.size() == 0; + final boolean activeParser = parser != null; + final boolean noDialAction = action == null; + if (noBranches && activeParser && noDialAction) { + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + } + } + } else { + fsm.transition(message, hangingUp); + } + } + + private void onEndMessage(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + //Because of RMS issue https://github.com/RestComm/mediaserver/issues/158 we cannot have List for waitUrl + if (playWaitUrlPending && conferenceWaitUris != null && conferenceWaitUris.size() > 0) { + if (logger.isInfoEnabled()) { + String msg = String.format("End tag received, playWaitUrlPending is %s, conferenceWaitUris.size() %d",playWaitUrlPending, conferenceWaitUris.size()); + logger.info(msg); + } + fsm.transition(conferenceWaitUris, conferencing); + return; + } + if (callState.equals(CallStateChanged.State.COMPLETED) || callState.equals(CallStateChanged.State.CANCELED)) { + if(logger.isInfoEnabled()) { + String msg = String.format("End tag received, Call state %s , VI state %s will move to finished state",callState, fsm.state()); + logger.info(msg); + } + fsm.transition(message, finished); + } else { + if (!isParserFailed) { + if(logger.isInfoEnabled()) { + logger.info("End tag received will move to hangup the call, VI state: "+fsm.state()); + } + fsm.transition(message, hangingUp); + } else { + if(logger.isInfoEnabled()) { + logger.info("End tag received but parser failed earlier so hangup would have been already sent to the call"); + } + } + } + } + + private void onTagMessage(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + verb = (Tag) message; + if (logger.isDebugEnabled()) { + logger.debug("Tag received, name: "+verb.name()+", text: "+verb.text()); + } + + // if 200 ok delay is enabled we need to answer only the calls + // which are having any further call enabler verbs in their RCML. + if(enable200OkDelay && callWaitingForAnswer && Verbs.isThisVerbCallEnabler(verb)){ + if(logger.isInfoEnabled()) { + logger.info("Tag received, but callWaitingForAnswer: will tell call to stop waiting"); + } + callWaitingForAnswerPendingTag = verb; + call.tell(new StopWaiting(), self()); + } else { + if (playWaitUrlPending) { + if (!(Verbs.play.equals(verb.name()) || Verbs.say.equals(verb.name()))) { + if (logger.isInfoEnabled()) { + logger.info("Tag for waitUrl is neither Play or Say"); + } + fsm.transition(message, hangingUp); + } + if (Verbs.say.equals(verb.name())) { + fsm.transition(message, checkingCache); + } else if (Verbs.play.equals(verb.name())) { + fsm.transition(message, caching); + } + return; + } + if (CallStateChanged.State.RINGING == callState) { + if (Verbs.reject.equals(verb.name())) { + fsm.transition(message, rejecting); + } else if (Verbs.pause.equals(verb.name())) { + fsm.transition(message, pausing); + } else { + fsm.transition(message, initializingCall); + } + } else if (Verbs.dial.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + action = verb.attribute(GatherAttributes.ATTRIBUTE_ACTION); + if (action != null && dialActionExecuted) { + //We have a new Dial verb that contains Dial Action URL again. + //We set dialActionExecuted to false in order to execute Dial Action again + dialActionExecuted = false; + } + dialRecordAttribute = verb.attribute("record"); + fsm.transition(message, startDialing); + } else if (Verbs.fax.equals(verb.name())) { + fsm.transition(message, caching); + } else if (Verbs.play.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + fsm.transition(message, caching); + } else if (Verbs.say.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + // fsm.transition(message, synthesizing); + fsm.transition(message, checkingCache); + } else if (Verbs.gather.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + gatherVerb = verb; + fsm.transition(message, processingGatherChildren); + } else if (Verbs.pause.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + fsm.transition(message, pausing); + } else if (Verbs.hangup.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + if (logger.isInfoEnabled()) { + String msg = String.format("Next verb is Hangup, current state is %s , callInfo state %s", fsm.state(), callInfo.state()); + logger.info(msg); + } + if (is(finishDialing)) { + fsm.transition(message, finished); + } else { + fsm.transition(message, hangingUp); + } + } else if (Verbs.redirect.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + fsm.transition(message, redirecting); + } else if (Verbs.record.equals(verb.name()) && callState != CallStateChanged.State.COMPLETED) { + fsm.transition(message, creatingRecording); + } else if (Verbs.sms.equals(verb.name())) { + + //Check if Outbound SMS is allowed + ExtensionController ec = ExtensionController.getInstance(); + final IExtensionFeatureAccessRequest far = new FeatureAccessRequest(FeatureAccessRequest.Feature.OUTBOUND_SMS, accountId); + ExtensionResponse er = ec.executePreOutboundAction(far, this.extensions); + + if (er.isAllowed()) { + fsm.transition(message, creatingSmsSession); + ec.executePostOutboundAction(far, extensions); + } else { + if (logger.isDebugEnabled()) { + final String errMsg = "Outbound SMS is not Allowed"; + logger.debug(errMsg); + } + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 11001, "Outbound SMS is now allowed"); + notifications.addNotification(notification); + fsm.transition(message, rejecting); + ec.executePostOutboundAction(far, extensions); + return; + } + } else if (Verbs.email.equals(verb.name())) { + fsm.transition(message, sendingEmail); + } else { + invalidVerb(verb); + } + } + } + + private void onDiskCacheResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final DiskCacheResponse response = (DiskCacheResponse) message; + if (response.succeeded()) { + //Because of RMS issue https://github.com/RestComm/mediaserver/issues/158 we cannot have List for waitUrl + if (playWaitUrlPending) { + if (conferenceWaitUris == null) + conferenceWaitUris = new ArrayList(); + URI waitUrl = response.get(); + conferenceWaitUris.add(waitUrl); + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + return; + } + if (is(caching) || is(checkingCache)) { + if (Verbs.play.equals(verb.name()) || Verbs.say.equals(verb.name())) { + fsm.transition(message, playing); + } else if (Verbs.fax.equals(verb.name())) { + fsm.transition(message, faxing); + } else if (Verbs.email.equals(verb.name())) { + fsm.transition(message, sendingEmail); + } + } else if (is(processingGatherChildren)) { + fsm.transition(message, processingGatherChildren); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("DiskCacheResponse is " + response.toString()); + } + if (is(checkingCache) || is(processingGatherChildren)) { + fsm.transition(message, synthesizing); + } else { + if(response.cause() != null){ + Notification notification = notification(WARNING_NOTIFICATION, 13233, response.cause().getMessage()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + sendMail(notification); + } + fsm.transition(message, hangingUp); + } + } + } + + private void onCallManagerResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final CallManagerResponse response = (CallManagerResponse) message; + if (response.succeeded()) { + if (is(startDialing)) { + fsm.transition(message, processingDialChildren); + } else if (is(processingDialChildren)) { + fsm.transition(message, processingDialChildren); + } + } else { + if (logger.isDebugEnabled()) { + String msg = String.format("CallManager failed to create Call for %s, current state %s, dialChilder.size %s, dialBranches.size %s", response.getCreateCall().to(), fsm.state().toString(), dialChildren.size(), dialBranches.size()); + logger.debug(msg); + } + if (dialChildren != null && dialChildren.size() > 0) { + fsm.transition(message, processingDialChildren); + } else { + fsm.transition(message, hangingUp); + } + } + } + + private void onSpeechSynthesizerResponse(Object message) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (is(acquiringSynthesizerInfo)) { + fsm.transition(message, acquiringCallInfo); + } else if (is(processingGatherChildren) || processingGather) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + if (response.succeeded()) { + fsm.transition(message, processingGatherChildren); + } else { + fsm.transition(message, hangingUp); + } + } else if (is(synthesizing)) { + final SpeechSynthesizerResponse response = (SpeechSynthesizerResponse) message; + if (response.succeeded()) { + fsm.transition(message, caching); + } else { + fsm.transition(message, hangingUp); + } + } + } + + private void onCallResponse(Object message, State state) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + if (forking.equals(state)) { + // Allow updating of the callInfo at the VoiceInterpreter so that we can do Dial SIP Screening + // (https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out) accurately from latest + // response received + final CallResponse response = (CallResponse) message; + // Check from whom is the message (initial call or outbound call) and update info accordingly + if (sender == call) { + callInfo = response.get(); + } else { + outboundCall = sender; + outboundCallInfo = response.get(); + } + } else if (acquiringCallInfo.equals(state)) { + final CallResponse response = (CallResponse) message; + // Check from whom is the message (initial call or outbound call) and update info accordingly + if (sender == call) { + callInfo = response.get(); + if (callInfo.state() == CallStateChanged.State.CANCELED || (callInfo.invite() != null && callInfo.invite().getSession().getState().equals(SipSession.State.TERMINATED))) { + fsm.transition(message, finished); + return; + } else { + call.tell(new Observe(self()), self()); + //Enable Monitoring Service for the call + if (monitoring != null) + call.tell(new Observe(monitoring), self()); + } + } else { + outboundCallInfo = response.get(); + } + + final String direction = callInfo.direction(); + if ("inbound".equals(direction)) { + if (rcml!=null && !rcml.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("System app is present will proceed to ready state, system app: "+rcml); + } + createInitialCallRecord((CallResponse) message); + fsm.transition(message, ready); + } else { + fsm.transition(message, downloadingRcml); + } + } else { + fsm.transition(message, initializingCall); + } + } else if (acquiringOutboundCallInfo.equals(state)) { + final CallResponse response = (CallResponse) message; + this.outboundCallInfo = response.get(); + fsm.transition(message, creatingBridge); + } + } + + private void onDownloaderResponse(Object message, State state) throws IOException, TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final DownloaderResponse response = (DownloaderResponse) message; + if (logger.isDebugEnabled()) { + logger.debug("Download Rcml response succeeded " + response.succeeded()); + if (response.get() != null ) + logger.debug("statusCode " + response.get().getStatusCode()); + } + if (response.succeeded() && HttpStatus.SC_OK == response.get().getStatusCode()) { + if (continuousGathering.equals(state)) { + //no need change state + return; + } + if (conferencing.equals(state)) { + //This is the downloader response for Conferencing waitUrl + if (parser != null) { + getContext().stop(parser); + parser = null; + } + final String type = response.get().getContentType(); + if (type != null) { + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + parser = parser(response.get().getContentAsString()); + } else if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { + parser = parser("" + request.getUri() + ""); + } else if (type.contains("text/plain")) { + parser = parser("" + response.get().getContentAsString() + ""); + } + } else { + //If the waitUrl is invalid then move to notFound + fsm.transition(message, hangingUp); + } + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + return; + } + if (dialBranches == null || dialBranches.size()==0) { + if(logger.isInfoEnabled()) { + logger.info("Downloader response is success, moving to Ready state"); + } + fsm.transition(message, ready); + } else { + return; + } + } else if (downloadingRcml.equals(state) && fallbackUrl != null) { + fsm.transition(message, downloadingFallbackRcml); + } else if (response.succeeded() && HttpStatus.SC_NOT_FOUND == response.get().getStatusCode()) { + fsm.transition(message, notFound); + } else { + call.tell(new CallFail(response.error()), self()); +// fsm.transition(message, finished); + } + } + + private void onCallStateChanged(Object message, ActorRef sender) throws TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { + final CallStateChanged event = (CallStateChanged) message; + if (sender == call) + callState = event.state(); + else + if(event.sipResponse()!=null && event.sipResponse()>=400){ + outboundCallResponse = event.sipResponse(); + } + if(logger.isInfoEnabled()){ + logger.info("VoiceInterpreter received CallStateChanged event: "+event+ " from "+(sender == call? "call" : "outboundCall")+ ", sender path: " + sender.path() +", current VI state: "+fsm.state() +" current outboundCall actor is: "+outboundCall); + } + + switch (event.state()) { + case QUEUED: + //Do nothing + break; + case RINGING: + if (logger.isInfoEnabled()) { + String msg = String.format("Got 180 Ringing from outbound call %s",sender); + logger.info(msg); + } + break; + case CANCELED: + if (is(initializingBridge) || is(acquiringOutboundCallInfo) || is(bridging) || is(bridged)) { + //This is a canceled branch from a previous forking call. We need to destroy the branch +// removeDialBranch(message, sender); + callManager.tell(new DestroyCall(sender), self()); + return; + } else { + if (enable200OkDelay && dialBranches != null && sender.equals(call)) { + if (callRecord != null) { + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + callRecord = records.getCallDetailRecord(callRecord.getSid()); + callRecord = callRecord.setStatus(callState.toString()); + records.updateCallDetailRecord(callRecord); + } + fsm.transition(message, finishDialing); + } else if (sender == call) { + //Move to finished state only if the call actor send the Cancel. + fsm.transition(message, finished); + } else { + //This is a Cancel from a dial branch previously canceled + + if (dialBranches != null && dialBranches.contains(sender)) { + removeDialBranch(message, sender); + checkDialBranch(message, sender, action); + } + else { + //case for LCM testTerminateDialForkCallWhileRinging_LCM_to_dial_branches + callState = event.state(); + } + } + } + break; + case BUSY: + if (is(forking)) { + if (sender == call) { + //Move to finishDialing to clear the call and cancel all branches + fsm.transition(message, finishDialing); + } else { + if (dialBranches != null && dialBranches.contains(sender)) { + removeDialBranch(message, sender); + } + if (dialBranches == null || dialBranches.size() == 0){ + // Stop playing the ringing tone from inbound call + msResponsePending = true; + call.tell(new StopMediaGroup(), self()); + } + checkDialBranch(message, sender, action); + return; + } + } if (is(initializingCall)) { + fsm.transition(message, finished); + } else { + fsm.transition(message, finishDialing); + return; + } + break; + case NOT_FOUND: + //Do nothing + break; + case NO_ANSWER: + //NOANSWER calls should be canceled. At CANCELED event will be removed from + //dialBranches and will be destroyed. + if (is(bridging) || (is(bridged) && !sender.equals(call))) { + fsm.transition(message, finishDialing); + } else if (is(forking)){ + if (!sender.equals(call)) { + //One of the dial branches sent NO-ANSWER and we should ask to CANCEL +// sender.tell(new Cancel(), self()); + } + } else if (is(finishDialing)) { + if ((dialBranches == null || dialBranches.size()==0) && sender.equals(call)) { + //TODO HERE + logger.info("No-Answer event received, and dialBrances is either null or 0 size, sender: "+sender.path()+", vi state: "+fsm.state()); + checkDialBranch(message, sender, action); + } + } + if (is(initializingCall)) { + sender.tell(new Hangup(), self()); + } + break; + case FAILED: + if (!sender.equals(call)) { + if (dialBranches != null && dialBranches.contains(sender)) { + dialBranches.remove(sender); + } + checkDialBranch(message,sender,action); + } else if (sender.equals(call)) { + fsm.transition(message, finished); + } + break; + case COMPLETED: + //NO_ANSWER, COMPLETED and FAILED events are handled the same + if (logger.isInfoEnabled()) { + String msg = String.format("OnCallStateChanged, VI state %s, received %s, is it from inbound call: %s",fsm.state().toString(), callState.toString(), sender.equals(call)); + logger.info(msg); + } + if (is(bridging) || is(bridged)) { + if (sender == outboundCall || sender == call) { + if(logger.isInfoEnabled()) { + String msg = String.format("Received CallStateChanged COMPLETED from call %s, current fsm state %s, will move to finishDialingState ", sender(), fsm.state()); + logger.info(msg); + } + fsm.transition(message, finishDialing); + } else { + if (dialBranches != null && dialBranches.contains(sender)) { + removeDialBranch(message, sender); + } + callManager.tell(new DestroyCall(sender()), self()); + } + return; + } + else + // changed for https://bitbucket.org/telestax/telscale-restcomm/issue/132/ so that we can do Dial SIP Screening + if (is(forking) && ((dialBranches != null && dialBranches.contains(sender)) || outboundCall == null)) { + if (!sender.equals(call)) { + removeDialBranch(message, sender); + //Properly clean up FAILED or BUSY outgoing calls + //callManager.tell(new DestroyCall(sender), self()); + checkDialBranch(message,sender,action); + return; + } else { + fsm.transition(message, finishDialing); + } + } else if (is(creatingRecording)) { + fsm.transition(message, finishRecording); + } else if ((is(bridged) || is(forking)) && call == sender()) { + if (!dialActionExecuted) { + fsm.transition(message, finishDialing); + } + } else if (is(finishDialing)) { + if (sender.equals(call)) { + fsm.transition(message, finished); + } else { + checkDialBranch(message, sender(), action); + } + break; + } else if (is(conferencing) || is(finishConferencing)) { + //If the CallStateChanged.Completed event from the Call arrived before the ConferenceStateChange.Completed + //event, then return and wait for the FinishConferencing to deal with the event (either execute dial action or + //get next verb from parser + if (logger.isInfoEnabled()) { + logger.info("VoiceInterpreter received CallStateChanged.Completed VI in: " + fsm.state() + " state, will return and wait for ConferenceStateChanged.Completed event"); + } + return; + } else { + if (!is(finishDialing) && !is(finished)) + fsm.transition(message, finished); + } + break; + case WAIT_FOR_ANSWER: + case IN_PROGRESS: + if(call!=null && (call == sender) && event.state().equals(CallStateChanged.State.WAIT_FOR_ANSWER)){ + callWaitingForAnswer = true; + } + if (is(initializingCall) || is(rejecting)) { + if (parser != null) { + //This is an inbound call + fsm.transition(message, ready); + } else { + //This is a REST API created outgoing call + fsm.transition(message, downloadingRcml); + } + } else if (is(forking)) { + if (outboundCall == null || !sender.equals(call)) { + if (logger.isInfoEnabled()) { + String msg = String.format("Got CallStateChanged.InProgress while forking, from outbound call %s, will proceed to cancel other branches", sender()); + logger.info(msg); + } + outboundCall = sender; + fsm.transition(message, acquiringOutboundCallInfo); + } + } else if (is(conferencing)) { + // Call left the conference successfully + if (!liveCallModification) { + // Hang up the call + final Hangup hangup = new Hangup(); + call.tell(hangup, sender); + } else { + // XXX start processing new RCML and give instructions to call + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + } + } else if (enable200OkDelay && sender.equals(call) && event.state().equals(CallStateChanged.State.IN_PROGRESS) && callWaitingForAnswerPendingTag != null) { + if (logger.isInfoEnabled()) { + logger.info("Waiting call is inProgress we can proceed to the pending tag execution"); + } + callWaitingForAnswer = false; + onTagMessage(callWaitingForAnswerPendingTag); + } + // Update the storage for conferencing. + if (callRecord != null && !is(initializingCall) && !is(rejecting)) { + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + callRecord = records.getCallDetailRecord(callRecord.getSid()); + callRecord = callRecord.setStatus(callState.toString()); + records.updateCallDetailRecord(callRecord); + } + break; + } + } + + private void removeDialBranch(Object message, ActorRef sender) { + //Just remove the branch from dialBranches and send the CANCEL + //Later at onCallStateChanged.CANCEL we should ask call manager to destroy call and + //either execute dial action or ask parser for next verb + CallStateChanged.State state = null; + if (message instanceof CallStateChanged) { + state = ((CallStateChanged)message).state(); + } else if (message instanceof ReceiveTimeout) { + state = CallStateChanged.State.NO_ANSWER; + } + if(logger.isInfoEnabled()) { + logger.info("Dial branch new call state: " + state + " call path: " + sender().path() + " VI state: " + fsm.state()); + } + if (state != null && !state.equals(CallStateChanged.State.CANCELED)) { + if (logger.isInfoEnabled()) { + logger.info("At removeDialBranch() will cancel call: "+sender.path()+", isTerminated: "+sender.isTerminated()); + } + sender.tell(new Cancel(), self()); + } + if (outboundCall != null && outboundCall.equals(sender)) { + outboundCall = null; + } + if (dialBranches != null && dialBranches.contains(sender)) + dialBranches.remove(sender); + } + + private void checkDialBranch(Object message, ActorRef sender, Attribute attribute) { + CallStateChanged.State state = null; + if (message instanceof CallStateChanged) { + state = ((CallStateChanged)message).state(); + } else if (message instanceof ReceiveTimeout) { + state = CallStateChanged.State.NO_ANSWER; + } + + if (dialBranches == null || dialBranches.size() == 0) { + dialBranches = null; + + if (attribute == null) { + if (logger.isInfoEnabled()) { + logger.info("Attribute is null, will destroy call and ask for the next verb from parser"); + } + if (sender != null && !sender.equals(call)) { + callManager.tell(new DestroyCall(sender), self()); + } + // VI cannot move to next verb if media still being reproduced by media server + // GetNextVerb is skipped while StopMediaGroup request is sent to media server + // RCML Parser/VI activity continues when media server successful response is received + if (parser != null && !msResponsePending) { + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, self()); + } + } else { + if (logger.isInfoEnabled()) { + logger.info("Executing Dial Action for inbound call"); + } + if (sender.equals(call)) { + executeDialAction(message, outboundCall); + } else { + executeDialAction(message, sender); + } + if (sender != null && !sender.equals(call)) { + if (logger.isInfoEnabled()) { + logger.info("Will destroy sender"); + } + callManager.tell(new DestroyCall(sender), self()); + } + } + if (bridge != null) { + // Stop the bridge + bridge.tell(new StopBridge(liveCallModification), self()); + recordingCall = false; + bridge = null; + } + } else if (state != null && (state.equals(CallStateChanged.State.BUSY) || + state.equals(CallStateChanged.State.CANCELED) || + state.equals(CallStateChanged.State.FAILED))) { + callManager.tell(new DestroyCall(sender), self()); + } + } + + private void onBridgeManagerResponse(BridgeManagerResponse message, ActorRef self, ActorRef sender) throws Exception { + if (is(creatingBridge)) { + this.bridge = message.get(); + fsm.transition(message, initializingBridge); + } + } + + private void onBridgeStateChanged(BridgeStateChanged message, ActorRef self, ActorRef sender) throws Exception { + switch (message.getState()) { + case READY: + if (is(initializingBridge)) { + fsm.transition(message, bridging); + } + break; + case BRIDGED: + if (is(bridging)) { + fsm.transition(message, bridged); + } + break; + + case FAILED: + if (is(initializingBridge)) { + fsm.transition(message, hangingUp); + } + default: + break; + } + } + + private void onGetRelatedCall(GetRelatedCall message, ActorRef self, ActorRef sender) { + final ActorRef callActor = message.call(); + if (is(forking)) { + sender.tell(dialBranches, self); + return; + } + if (outboundCall != null) { + if (callActor.equals(outboundCall)) { + sender.tell(call, self); + } else if (callActor.equals(call)) { + sender.tell(outboundCall, self); + } + } else { + // If previously that was a p2p call that changed to conference (for hold) + // and now it changes again to a new url, the outbound call is null since + // When we joined the call to the conference, we made outboundCall = null; + sender.tell(new org.restcomm.connect.telephony.api.NotFound(), sender); + } + } + + private void onCallHoldStateChange(CallHoldStateChange message, ActorRef sender){ + if (logger.isInfoEnabled()) { + logger.info("CallHoldStateChange received, state: " + message.state()); + } + if (asImsUa){ + if (sender.equals(outboundCall)) { + call.tell(message, self()); + } else if (sender.equals(call)) { + outboundCall.tell(message, self()); + } + } + } + + private void conferenceStateModeratorPresent(final Object message) { + if(logger.isInfoEnabled()) { + logger.info("VoiceInterpreter#conferenceStateModeratorPresent will unmute the call: " + call.path().toString()+", direction: "+callInfo.direction()); + } + call.tell(new Unmute(), self()); + + if (confSubVoiceInterpreter != null) { + if(logger.isInfoEnabled()) { + logger.info("VoiceInterpreter stopping confSubVoiceInterpreter"); + } + + // Stop the conference back ground music + final StopInterpreter stop = new StopInterpreter(); + confSubVoiceInterpreter.tell(stop, self()); + } + } + + List parameters() { + final List parameters = new ArrayList(); + final String callSid = callInfo.sid().toString(); + parameters.add(new BasicNameValuePair("CallSid", callSid)); + parameters.add(new BasicNameValuePair("InstanceId", restcommConfiguration.getMain().getInstanceId())); + if (outboundCallInfo != null) { + final String outboundCallSid = outboundCallInfo.sid().toString(); + parameters.add(new BasicNameValuePair("OutboundCallSid", outboundCallSid)); + } + final String accountSid = accountId.toString(); + parameters.add(new BasicNameValuePair("AccountSid", accountSid)); + final String from = e164(callInfo.from()); + parameters.add(new BasicNameValuePair("From", from)); + final String to = e164(callInfo.to()); + parameters.add(new BasicNameValuePair("To", to)); + final String state = callState.toString(); + parameters.add(new BasicNameValuePair("CallStatus", state)); + parameters.add(new BasicNameValuePair("ApiVersion", version)); + final String direction = callInfo.direction(); + parameters.add(new BasicNameValuePair("Direction", direction)); + final String callerName = (callInfo.fromName() == null || callInfo.fromName().isEmpty()) ? "null" : callInfo.fromName(); + parameters.add(new BasicNameValuePair("CallerName", callerName)); + final String forwardedFrom = (callInfo.forwardedFrom() == null || callInfo.forwardedFrom().isEmpty()) ? "null" : callInfo.forwardedFrom(); + parameters.add(new BasicNameValuePair("ForwardedFrom", forwardedFrom)); + parameters.add(new BasicNameValuePair("CallTimestamp", callInfo.dateCreated().toString())); + if (referTarget != null) { + parameters.add(new BasicNameValuePair("ReferTarget", referTarget)); + } + if (transferor != null) { + parameters.add(new BasicNameValuePair("Transferor", transferor)); + } + if (transferee != null) { + parameters.add(new BasicNameValuePair("Transferee", transferee)); + } + // logger.info("Type " + callInfo.type()); + SipServletResponse lastResponse = callInfo.lastResponse(); + if (CreateCallType.SIP == callInfo.type()) { + // Adding SIP OUT Headers and SipCallId for + // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out + // logger.info("lastResponse " + lastResponse); + if (lastResponse != null) { + final int statusCode = lastResponse.getStatus(); + final String method = lastResponse.getMethod(); + // See https://www.twilio.com/docs/sip/receiving-sip-headers + // Headers on the final SIP response message (any 4xx or 5xx message or the final BYE/200) are posted to the + // Dial action URL. + if ((statusCode >= 400 && "INVITE".equalsIgnoreCase(method)) + || (statusCode >= 200 && statusCode < 300 && "BYE".equalsIgnoreCase(method))) { + final String sipCallId = lastResponse.getCallId(); + parameters.add(new BasicNameValuePair("DialSipCallId", sipCallId)); + parameters.add(new BasicNameValuePair("DialSipResponseCode", "" + statusCode)); + processCustomAndDiversionHeaders(lastResponse, "DialSipHeader_", parameters); + } + } + } + + if (lastResponse == null) { + // Restcomm VoiceInterpreter should check the INVITE for custom headers and pass them to RVD + // https://telestax.atlassian.net/browse/RESTCOMM-710 + final SipServletRequest invite = callInfo.invite(); + // For outbound calls created with Calls REST API, the invite at this point will be null + if (invite != null) { + processCustomAndDiversionHeaders(invite, "SipHeader_", parameters); + + } + } else { + processCustomAndDiversionHeaders(lastResponse, "SipHeader_", parameters); + } + + return parameters; + } + + private void processCustomAndDiversionHeaders(SipServletMessage sipMessage, String prefix, List parameters) { + Iterator headerNames = sipMessage.getHeaderNames(); + while (headerNames.hasNext()) { + String headerName = headerNames.next(); + if (headerName.startsWith("X-")) { + if (logger.isDebugEnabled()) { + logger.debug("%%%%%%%%%%% Identified customer header: " + headerName); + } + parameters.add(new BasicNameValuePair(prefix + headerName, sipMessage.getHeader(headerName))); + } else if (headerName.startsWith("Diversion")) { + + final String sipDiversionHeader = sipMessage.getHeader(headerName); + if (logger.isDebugEnabled()) { + logger.debug("%%%%%%%%%%% Identified diversion header: " + sipDiversionHeader); + } + parameters.add(new BasicNameValuePair(prefix + headerName, sipDiversionHeader)); + + try { + forwardedFrom = sipDiversionHeader.substring(sipDiversionHeader.indexOf("sip:") + 4, + sipDiversionHeader.indexOf("@")); + + for(int i=0; i < parameters.size(); i++) { + if (parameters.get(i).getName().equals("ForwardedFrom")) { + if (parameters.get(i).getValue().equals("null")) { + parameters.remove(i); + parameters.add(new BasicNameValuePair("ForwardedFrom", forwardedFrom)); + break; + } else { + // Not null, so it's not going to be overwritten with Diversion Header + break; + } + } + } + } catch (Exception e) { + logger.warning("Error parsing SIP Diversion header"+ e.getMessage()); + } + } + } + } + + private abstract class AbstractAction implements Action { + protected final ActorRef source; + + public AbstractAction(final ActorRef source) { + super(); + this.source = source; + } + + protected Tag conference(final Tag container) { + final List children = container.children(); + for (final Tag child : children) { + if (Nouns.conference.equals(child.name())) { + return child; + } + } + return null; + } + + protected Tag video(final Tag container) { + final List children = container.children(); + for (final Tag child : children) { + if (Nouns.video.equals(child.name())) { + return child; + } + } + return null; + } + } + + private final class InitializingCall extends AbstractAction { + public InitializingCall(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + + if (CallResponse.class.equals(klass)) { + // Update the interpreter state. + final CallResponse response = (CallResponse) message; + callInfo = response.get(); + callState = callInfo.state(); + if (callState.name().equalsIgnoreCase(CallStateChanged.State.IN_PROGRESS.name())) { + final CallStateChanged event = new CallStateChanged(CallStateChanged.State.IN_PROGRESS); + source.tell(event, source); + // fsm.transition(event, acquiringCallMediaGroup); + return; + } + + // Update the storage. + if (callRecord != null) { + callRecord = callRecord.setStatus(callState.toString()); + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + records.updateCallDetailRecord(callRecord); + } + + // Update the application. + callback(); + + // Start dialing. + call.tell(new Dial(), source); + // Set the timeout period. + final UntypedActorContext context = getContext(); + context.setReceiveTimeout(Duration.create(timeout, TimeUnit.SECONDS)); + } else if (Tag.class.equals(klass)) { + // Update the interpreter state. + verb = (Tag) message; + + // Answer the call. + boolean confirmCall = true; + if (enable200OkDelay && Verbs.dial.equals(verb.name())) { + confirmCall=false; + } + call.tell(new Answer(callRecord.getSid(),confirmCall), source); + } + } + } + + private final class DownloadingRcml extends AbstractAction { + public DownloadingRcml(final ActorRef source) { + super(source); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (CallResponse.class.equals(klass)) { + createInitialCallRecord((CallResponse) message); + } + // Ask the downloader to get us the application that will be executed. + final List parameters = parameters(); + request = new HttpRequestDescriptor(url, method, parameters); + downloader.tell(request, source); + } + } + + private void createInitialCallRecord(CallResponse message) { + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + final CallResponse response = message; + callInfo = response.get(); + callState = callInfo.state(); + if (callInfo.direction().equals("inbound")) { + callRecord = records.getCallDetailRecord(callInfo.sid()); + if (callRecord == null) { + // Create a call detail record for the call. + final CallDetailRecord.Builder builder = CallDetailRecord.builder(); + builder.setSid(callInfo.sid()); + builder.setInstanceId(restcommConfiguration.getInstance().getMain().getInstanceId()); + builder.setDateCreated(callInfo.dateCreated()); + builder.setAccountSid(accountId); + builder.setTo(callInfo.to()); + if (callInfo.fromName() != null) { + builder.setCallerName(callInfo.fromName()); + } else { + builder.setCallerName("Unknown"); + } + if (callInfo.from() != null) { + builder.setFrom(callInfo.from()); + } else { + builder.setFrom("Unknown"); + } + builder.setForwardedFrom(callInfo.forwardedFrom()); + builder.setPhoneNumberSid(phoneId); + builder.setStatus(callState.toString()); + final DateTime now = DateTime.now(); + builder.setStartTime(now); + builder.setDirection(callInfo.direction()); + builder.setApiVersion(version); + builder.setPrice(new BigDecimal("0.00")); + builder.setMuted(false); + builder.setOnHold(false); + // TODO implement currency property to be read from Configuration + builder.setPriceUnit(Currency.getInstance("USD")); + final StringBuilder buffer = new StringBuilder(); + buffer.append("/").append(version).append("/Accounts/"); + buffer.append(accountId.toString()).append("/Calls/"); + buffer.append(callInfo.sid().toString()); + final URI uri = URI.create(buffer.toString()); + builder.setUri(uri); + + builder.setCallPath(call.path().toString()); + + callRecord = builder.build(); + records.addCallDetailRecord(callRecord); + } + + // Update the application. + callback(); + } + } + + private final class DownloadingFallbackRcml extends AbstractAction { + public DownloadingFallbackRcml(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + // Notify the account of the issue. + if (DownloaderResponse.class.equals(klass)) { + final DownloaderResponse result = (DownloaderResponse) message; + final Throwable cause = result.cause(); + Notification notification = null; + if (cause instanceof ClientProtocolException) { + notification = notification(ERROR_NOTIFICATION, 11206, cause.getMessage()); + } else if (cause instanceof IOException) { + notification = notification(ERROR_NOTIFICATION, 11205, cause.getMessage()); + } else if (cause instanceof URISyntaxException) { + notification = notification(ERROR_NOTIFICATION, 11100, cause.getMessage()); + } + if (notification != null) { + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + sendMail(notification); + } + } + // Try to use the fall back url and method. + final List parameters = parameters(); + request = new HttpRequestDescriptor(fallbackUrl, fallbackMethod, parameters); + downloader.tell(request, source); + } + } + + private final class Ready extends AbstractAction { + public Ready(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws IOException { + final UntypedActorContext context = getContext(); + final State state = fsm.state(); + if (initializingCall.equals(state)) { + // Update the interpreter state. + final CallStateChanged event = (CallStateChanged) message; + callState = event.state(); + + // Update the application. + callback(); + + // Update the storage. + if (callRecord != null) { + final CallDetailRecordsDao records = storage.getCallDetailRecordsDao(); + callRecord = records.getCallDetailRecord(callRecord.getSid()); + callRecord = callRecord.setStatus(callState.toString()); + callRecord = callRecord.setStartTime(DateTime.now()); + callRecord = callRecord.setForwardedFrom(forwardedFrom); + records.updateCallDetailRecord(callRecord); + } + + // Handle pending verbs. + source.tell(verb, source); + return; + } else if (downloadingRcml.equals(state) || downloadingFallbackRcml.equals(state) || redirecting.equals(state) + || continuousGathering.equals(state) || finishGathering.equals(state) || finishRecording.equals(state) || sendingSms.equals(state) + || finishDialing.equals(state) || finishConferencing.equals(state) || is(forking)) { + response = ((DownloaderResponse) message).get(); + if (parser != null) { + context.stop(parser); + parser = null; + } + final String type = response.getContentType(); + if (type != null) { + if (type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { + parser = parser(response.getContentAsString()); + } else if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { + parser = parser("" + request.getUri() + ""); + } else if (type.contains("text/plain")) { + parser = parser("" + response.getContentAsString() + ""); + } + } else { + if (call != null) { + call.tell(new Hangup(outboundCallResponse), null); + } + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return; + } + } else if ((message instanceof CallResponse) && (rcml != null && !rcml.isEmpty())) { + if (parser != null) { + context.stop(parser); + parser = null; + } + parser = parser(rcml); + } else if (pausing.equals(state)) { + context.setReceiveTimeout(Duration.Undefined()); + } + // Ask the parser for the next action to take. + final GetNextVerb next = new GetNextVerb(); + if (parser != null) { + parser.tell(next, source); + } else if(logger.isInfoEnabled()) { + logger.info("Parser is null"); + } + + } + } + + private final class NotFound extends AbstractAction { + public NotFound(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final DownloaderResponse response = (DownloaderResponse) message; + if (logger.isDebugEnabled()) { + logger.debug("response succeeded " + response.succeeded() + ", statusCode " + response.get().getStatusCode()); + } + final Notification notification = notification(WARNING_NOTIFICATION, 21402, "URL Not Found : " + + response.get().getURI()); + final NotificationsDao notifications = storage.getNotificationsDao(); + notifications.addNotification(notification); + // Hang up the call. + call.tell(new org.restcomm.connect.telephony.api.NotFound(), source); + } + } + + private final class Rejecting extends AbstractAction { + public Rejecting(final ActorRef source) { + super(source); + } + + @Override + public void execute(final Object message) throws Exception { + final Class klass = message.getClass(); + if (Tag.class.equals(klass)) { + verb = (Tag) message; + } + String reason = "rejected"; + Attribute attribute = verb.attribute("reason"); + if (attribute != null) { + reason = attribute.value(); + if (reason != null && !reason.isEmpty()) { + if ("rejected".equalsIgnoreCase(reason)) { + reason = "rejected"; + } else if ("busy".equalsIgnoreCase(reason)) { + reason = "busy"; + } else { + reason = "rejected"; + } + } else { + reason = "rejected"; + } + } + // Reject the call. + call.tell(new Reject(reason), source); + } + } + + private abstract class AbstractDialAction extends AbstractAction { + public AbstractDialAction(final ActorRef source) { + super(source); + } + + protected String callerId(final Tag container) { + // Parse "from". + String callerId = null; + + // Issue 210: https://telestax.atlassian.net/browse/RESTCOMM-210 + final boolean useInitialFromAsCallerId = configuration.subset("runtime-settings").getBoolean("from-address-to-proxied-calls"); + + Attribute attribute = verb.attribute("callerId"); + if (attribute != null) { + callerId = attribute.value(); + if (callerId != null && !callerId.isEmpty()) { + callerId = e164(callerId); + if (callerId == null) { + callerId = verb.attribute("callerId").value(); + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(ERROR_NOTIFICATION, 13214, callerId + + " is an invalid callerId."); + notifications.addNotification(notification); + sendMail(notification); + final StopInterpreter stop = new StopInterpreter(); + source.tell(stop, source); + return null; + } + } + } + + if (callerId == null && useInitialFromAsCallerId) + callerId = callInfo.from(); + + return callerId; + } + + protected int timeout(final Tag container) { + int timeout = 30; + Attribute attribute = container.attribute("timeout"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + timeout = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 13212, value + + " is not a valid timeout value for "); + notifications.addNotification(notification); + } + } + } + return timeout; + } + + protected int timeLimit(final Tag container) { + int timeLimit = 14400; + Attribute attribute = container.attribute("timeLimit"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + timeLimit = Integer.parseInt(value); + } catch (final NumberFormatException exception) { + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 13216, value + + " is not a valid timeLimit value for "); + notifications.addNotification(notification); + } + } + } + return timeLimit; + } + + protected MediaAttributes.MediaType videoEnabled(final Tag container) { + boolean videoEnabled = false; + Attribute attribute = container.attribute("enable"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + videoEnabled = Boolean.valueOf(value); + } + } + if (videoEnabled) { + return MediaAttributes.MediaType.AUDIO_VIDEO; + } else { + return MediaAttributes.MediaType.AUDIO_ONLY; + } + } + + protected MediaAttributes.VideoMode videoMode(final Tag container){ + MediaAttributes.VideoMode videoMode = MediaAttributes.VideoMode.MCU; + Attribute attribute = container.attribute("mode"); + if (attribute != null) { + final String value = attribute.value(); + if (value != null && !value.isEmpty()) { + try { + videoMode = MediaAttributes.VideoMode.getValueOf(value); + } catch (IllegalArgumentException e) { + final NotificationsDao notifications = storage.getNotificationsDao(); + final Notification notification = notification(WARNING_NOTIFICATION, 15001, value + + " is not a valid mode value for